package world.respect import android.content.Context import androidx.room.Room import androidx.sqlite.driver.bundled.BundledSQLiteDriver import com.russhwolf.settings.Settings import com.russhwolf.settings.SharedPreferencesSettings import world.respect.shared.domain.phonenumber.IPhoneNumberUtil import world.respect.shared.domain.phonenumber.IPhoneNumberUtilAndroid import com.ustadmobile.core.domain.storage.GetOfflineStorageOptionsUseCase import com.ustadmobile.libcache.CachePathsProvider import com.ustadmobile.libcache.UstadCache import com.ustadmobile.libcache.UstadCacheBuilder import com.ustadmobile.libcache.connectivitymonitor.ConnectivityMonitorAndroid import com.ustadmobile.libcache.db.ClearNeighborsCallback import com.ustadmobile.libcache.db.UstadCacheDb import com.ustadmobile.libcache.downloader.EnqueueRunDownloadJobUseCase import com.ustadmobile.libcache.downloader.EnqueueRunDownloadJobUseCaseAndroid import com.ustadmobile.libcache.downloader.PinPublicationPrepareUseCase import com.ustadmobile.libcache.downloader.RunDownloadJobUseCase import com.ustadmobile.libcache.downloader.RunDownloadJobUseCaseImpl import com.ustadmobile.libcache.logging.NapierLoggingAdapter import com.ustadmobile.libcache.okhttp.UstadCacheInterceptor import com.ustadmobile.libcache.webview.OkHttpWebViewClient import io.github.aakira.napier.Napier import io.ktor.client.HttpClient import io.ktor.client.engine.okhttp.OkHttp import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.serialization.kotlinx.json.json import io.michaelrocks.libphonenumber.android.PhoneNumberUtil import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.io.files.Path import kotlinx.serialization.json.Json import okhttp3.Dispatcher import okhttp3.OkHttpClient import org.koin.android.ext.koin.androidApplication import org.koin.android.ext.koin.androidContext import org.koin.core.module.dsl.viewModelOf import org.koin.core.qualifier.named import org.koin.dsl.module import world.respect.app.config.RespectBuildConfig import world.respect.callback.AddSchoolDirectoryCallback import world.respect.credentials.passkey.CheckPasskeySupportUseCase import world.respect.credentials.passkey.CheckPasskeySupportUseCaseAndroidImpl import world.respect.credentials.passkey.CreatePasskeyUseCase import world.respect.credentials.passkey.CreatePasskeyUseCaseAndroidChannelHost import world.respect.credentials.passkey.CreatePasskeyUseCaseAndroidImpl import world.respect.credentials.passkey.GetCredentialUseCase import world.respect.credentials.passkey.GetCredentialUseCaseAndroidImpl import world.respect.credentials.passkey.VerifyDomainUseCase import world.respect.credentials.passkey.VerifyDomainUseCaseImpl import world.respect.credentials.passkey.password.SavePasswordUseCase import world.respect.credentials.passkey.request.CreatePublicKeyCredentialCreationOptionsJsonUseCase import world.respect.credentials.passkey.request.CreatePublicKeyCredentialRequestOptionsJsonUseCase import world.respect.credentials.passkey.request.EncodeUserHandleUseCase import world.respect.credentials.passkey.request.GetPasskeyProviderInfoUseCase import world.respect.credentials.password.SavePasswordUseCaseAndroidImpl import world.respect.datalayer.AuthTokenProvider import world.respect.datalayer.AuthenticatedUserPrincipalId import world.respect.datalayer.RespectAppDataSource import world.respect.datalayer.SchoolDataSource import world.respect.datalayer.SchoolDataSourceLocal import world.respect.datalayer.UidNumberMapper import world.respect.datalayer.db.RespectAppDataSourceDb import world.respect.datalayer.db.RespectAppDatabase import world.respect.datalayer.db.RespectSchoolDatabase import world.respect.datalayer.db.SchoolDataSourceDb import world.respect.datalayer.db.addCommonMigrations import world.respect.datalayer.db.networkvalidation.ExtendedDataSourceValidationHelperImpl import world.respect.datalayer.db.school.GetAuthenticatedPersonUseCase import world.respect.datalayer.db.school.domain.CheckPersonPermissionUseCaseDbImpl import world.respect.datalayer.db.school.writequeue.RemoteWriteQueueDbImpl import world.respect.datalayer.db.schooldirectory.SchoolDirectoryDataSourceDb import world.respect.datalayer.db.shared.PullSyncTrackerDbImpl import world.respect.datalayer.http.RespectAppDataSourceHttp import world.respect.datalayer.http.SchoolDataSourceHttp import world.respect.datalayer.networkvalidation.ExtendedDataSourceValidationHelper import world.respect.datalayer.repository.RespectAppDataSourceRepository import world.respect.datalayer.repository.SchoolDataSourceRepository import world.respect.datalayer.repository.school.pullsync.EnqueueRunPullSyncUseCaseAndroidImpl import world.respect.datalayer.repository.school.pullsync.RunPullSyncUseCase import world.respect.datalayer.repository.school.writequeue.DrainRemoteWriteQueueUseCase import world.respect.datalayer.repository.school.writequeue.EnqueueDrainRemoteWriteQueueUseCaseAndroidImpl import world.respect.datalayer.respect.model.SchoolDirectoryEntry import world.respect.datalayer.school.domain.CheckPersonPermissionUseCase import world.respect.datalayer.school.domain.GetWritableRolesListUseCase import world.respect.datalayer.school.domain.GetWritableRolesListUseCaseImpl import world.respect.datalayer.school.writequeue.EnqueueDrainRemoteWriteQueueUseCase import world.respect.datalayer.school.writequeue.EnqueueRunPullSyncUseCase import world.respect.datalayer.school.writequeue.RemoteWriteQueue import world.respect.datalayer.schooldirectory.SchoolDirectoryDataSourceLocal import world.respect.datalayer.shared.pullsync.PullSyncTracker import world.respect.datalayer.shared.XXHashUidNumberMapper import world.respect.lib.primarykeygen.PrimaryKeyGenerator import world.respect.lib.xapi.nanohttpd.XapiNanoHttpdApp import world.respect.lib.xapi.nanohttpd.XapiNanoHttpdResourceProvider import world.respect.libutil.ext.sanitizedForFilename import world.respect.libxxhash.XXHasher64Factory import world.respect.libxxhash.XXStringHasher import world.respect.libxxhash.jvmimpl.XXHasher64FactoryCommonJvm import world.respect.libxxhash.jvmimpl.XXStringHasherCommonJvm import world.respect.shared.domain.account.RespectAccount import world.respect.shared.domain.account.RespectAccountManager import world.respect.shared.domain.account.RespectAccountSchoolScopeLink import world.respect.shared.domain.account.RespectTokenManager import world.respect.shared.domain.account.child.AddChildAccountUseCase import world.respect.shared.domain.account.authenticatepassword.AuthenticatePasswordUseCase import world.respect.shared.domain.account.child.AddChildAccountUseCaseClient import world.respect.shared.domain.account.gettokenanduser.GetTokenAndUserProfileWithCredentialUseCase import world.respect.shared.domain.account.gettokenanduser.GetTokenAndUserProfileWithCredentialUseCaseClient import world.respect.shared.domain.account.invite.ApproveOrDeclineInviteRequestUseCase import world.respect.shared.domain.account.invite.GetInviteInfoUseCase import world.respect.shared.domain.account.invite.GetInviteInfoUseCaseClient import world.respect.shared.domain.account.invite.RedeemInviteUseCase import world.respect.shared.domain.account.invite.RedeemInviteUseCaseClient import world.respect.shared.domain.navigation.onaccountcreated.NavigateOnAccountCreatedUseCase import world.respect.shared.domain.account.passkey.EncodeUserHandleUseCaseImpl import world.respect.shared.domain.account.passkey.GetPasskeyProviderInfoUseCaseImpl import world.respect.shared.domain.account.passkey.GetActivePersonPasskeysClient import world.respect.shared.domain.account.passkey.GetActivePersonPasskeysUseCase import world.respect.shared.domain.account.passkey.LoadAaguidJsonUseCase import world.respect.shared.domain.account.passkey.LoadAaguidJsonUseCaseAndroid import world.respect.shared.domain.account.passkey.RevokePasskeyUseCase import world.respect.shared.domain.account.passkey.RevokePasskeyUseCaseClient import world.respect.shared.domain.account.passkey.VerifyPasskeyUseCase import world.respect.shared.domain.account.setpassword.EncryptPersonPasswordUseCase import world.respect.shared.domain.account.setpassword.EncryptPersonPasswordUseCaseImpl import world.respect.shared.domain.account.username.UsernameSuggestionUseCase import world.respect.shared.domain.account.username.UsernameSuggestionUseCaseClient import world.respect.shared.domain.account.username.checkusernameunique.CheckUsernameUniqueUseCase import world.respect.shared.domain.account.username.checkusernameunique.CheckUsernameUniqueUseCaseClient import world.respect.shared.domain.account.username.filterusername.FilterUsernameUseCase import world.respect.shared.domain.account.username.validateusername.ValidateUsernameUseCase import world.respect.shared.domain.account.validatepassword.ValidatePasswordUseCase import world.respect.shared.domain.account.validateqrbadge.ValidateQrCodeUseCase import world.respect.shared.domain.appversioninfo.GetAppVersionInfoUseCase import world.respect.shared.domain.appversioninfo.GetAppVersionInfoUseCaseAndroid import world.respect.shared.domain.clipboard.SetClipboardStringUseCase import world.respect.shared.domain.clipboard.SetClipboardStringUseCaseAndroid import world.respect.shared.domain.createlink.CreateInviteLinkUseCase import world.respect.shared.domain.devmode.GetDevModeEnabledUseCase import world.respect.shared.domain.devmode.SetDevModeEnabledUseCase import world.respect.shared.domain.school.LaunchCustomTabUseCaseAndroid import world.respect.shared.domain.getdeviceinfo.GetDeviceInfoUseCase import world.respect.shared.domain.getdeviceinfo.GetDeviceInfoUseCaseAndroid import world.respect.shared.domain.getwarnings.GetWarningsUseCase import world.respect.shared.domain.getwarnings.GetWarningsUseCaseAndroid import world.respect.shared.domain.launchapp.LaunchAppUseCase import world.respect.shared.domain.launchapp.LaunchAppUseCaseAndroid import world.respect.shared.domain.navigation.deeplink.CustomDeepLinkToUrlUseCase import world.respect.shared.domain.navigation.deeplink.UrlToCustomDeepLinkUseCase import world.respect.shared.domain.onboarding.ShouldShowOnboardingUseCase import world.respect.shared.domain.permissions.CheckSchoolPermissionsUseCase import world.respect.shared.domain.phonenumber.OnClickPhoneNumUseCase import world.respect.shared.domain.phonenumber.OnClickPhoneNumberUseCaseAndroid import world.respect.shared.domain.phonenumber.PhoneNumValidatorAndroid import world.respect.shared.domain.phonenumber.PhoneNumValidatorUseCase import world.respect.shared.domain.report.formatter.CreateGraphFormatterUseCase import world.respect.shared.domain.report.query.MockRunReportUseCaseClientImpl import world.respect.shared.domain.report.query.RunReportUseCase import world.respect.shared.domain.school.LaunchCustomTabUseCase import world.respect.shared.domain.school.RespectSchoolPath import world.respect.shared.domain.school.SchoolPrimaryKeyGenerator import world.respect.shared.domain.storage.CachePathsProviderAndroid import world.respect.shared.domain.storage.GetAndroidSdCardDirUseCase import world.respect.shared.domain.storage.GetOfflineStorageOptionsUseCaseAndroid import world.respect.shared.domain.storage.GetOfflineStorageSettingUseCase import world.respect.shared.domain.usagereporting.GetUsageReportingEnabledUseCase import world.respect.shared.domain.usagereporting.GetUsageReportingEnabledUseCaseAndroid import world.respect.shared.domain.usagereporting.SetUsageReportingEnabledUseCase import world.respect.shared.domain.usagereporting.SetUsageReportingEnabledUseCaseAndroid import world.respect.shared.domain.validateemail.ValidateEmailUseCase import world.respect.shared.generated.resources.Res import world.respect.shared.generated.resources.app_name import world.respect.shared.navigation.NavResultReturner import world.respect.shared.navigation.NavResultReturnerImpl import world.respect.shared.util.di.RespectAccountScopeId import world.respect.shared.util.di.SchoolDirectoryEntryScopeId import world.respect.shared.viewmodel.acknowledgement.AcknowledgementViewModel import world.respect.shared.viewmodel.app.appstate.SnackBarDispatcher import world.respect.shared.viewmodel.app.appstate.SnackBarFlowDispatcher import world.respect.shared.viewmodel.apps.detail.AppsDetailViewModel import world.respect.shared.viewmodel.apps.enterlink.EnterLinkViewModel import world.respect.shared.viewmodel.apps.launcher.AppLauncherViewModel import world.respect.shared.viewmodel.apps.list.AppListViewModel import world.respect.shared.viewmodel.assignment.detail.AssignmentDetailViewModel import world.respect.shared.viewmodel.assignment.edit.AssignmentEditViewModel import world.respect.shared.viewmodel.assignment.list.AssignmentListViewModel import world.respect.shared.viewmodel.enrollment.list.EnrollmentListViewModel import world.respect.shared.viewmodel.enrollment.edit.EnrollmentEditViewModel import world.respect.shared.viewmodel.clazz.detail.ClazzDetailViewModel import world.respect.shared.viewmodel.clazz.edit.ClazzEditViewModel import world.respect.shared.viewmodel.clazz.list.ClazzListViewModel import world.respect.shared.viewmodel.learningunit.detail.LearningUnitDetailViewModel import world.respect.shared.viewmodel.learningunit.list.LearningUnitListViewModel import world.respect.shared.viewmodel.manageuser.accountlist.AccountListViewModel import world.respect.shared.viewmodel.manageuser.acceptinvite.AcceptInviteViewModel import world.respect.shared.viewmodel.manageuser.enterpasswordsignup.EnterPasswordSignupViewModel import world.respect.shared.viewmodel.manageuser.getstarted.GetStartedViewModel import world.respect.shared.viewmodel.manageuser.howpasskeywork.HowPasskeyWorksViewModel import world.respect.shared.viewmodel.manageuser.enterinvitecode.EnterInviteCodeViewModel import world.respect.shared.viewmodel.manageuser.login.LoginViewModel import world.respect.shared.viewmodel.manageuser.otheroption.OtherOptionsViewModel import world.respect.shared.viewmodel.manageuser.otheroptionsignup.OtherOptionsSignupViewModel import world.respect.shared.viewmodel.manageuser.profile.SignupViewModel import world.respect.shared.viewmodel.manageuser.signup.CreateAccountViewModel import world.respect.shared.viewmodel.manageuser.termsandcondition.TermsAndConditionViewModel import world.respect.shared.viewmodel.manageuser.waitingforapproval.WaitingForApprovalViewModel import world.respect.shared.viewmodel.onboarding.OnboardingViewModel import world.respect.shared.viewmodel.person.changepassword.ChangePasswordViewModel import world.respect.shared.viewmodel.person.copycode.CopyInviteCodeViewModel import world.respect.shared.viewmodel.person.detail.PersonDetailViewModel import world.respect.shared.domain.biometric.BiometricAuthUseCase import world.respect.shared.domain.biometric.BiometricAuthUseCaseAndroidImpl import world.respect.shared.domain.createclass.CreateClassUseCase import world.respect.shared.domain.enrollments.UpdateClazzStudentXapiGroupUseCase import world.respect.shared.domain.navigation.deferreddeeplink.GetDeferredDeepLinkUseCase import world.respect.shared.domain.navigation.deeplink.InitDeepLinkUriProviderUseCase import world.respect.shared.domain.navigation.deeplink.InitDeepLinkUriProviderUseCaseAndroid import world.respect.shared.viewmodel.person.edit.PersonEditViewModel import world.respect.shared.viewmodel.person.list.PersonListViewModel import world.respect.shared.viewmodel.person.inviteperson.InvitePersonViewModel import world.respect.shared.viewmodel.person.qrcode.InviteQrViewModel import world.respect.shared.viewmodel.person.manageaccount.ManageAccountViewModel import world.respect.shared.viewmodel.person.passkeylist.PasskeyListViewModel import world.respect.shared.viewmodel.report.ReportViewModel import world.respect.shared.viewmodel.report.detail.ReportDetailViewModel import world.respect.shared.viewmodel.report.edit.ReportEditViewModel import world.respect.shared.viewmodel.report.filteredit.ReportFilterEditViewModel import world.respect.shared.viewmodel.report.indictor.detail.IndicatorDetailViewModel import world.respect.shared.viewmodel.report.indictor.edit.IndicatorEditViewModel import world.respect.shared.viewmodel.report.indictor.list.IndicatorListViewModel import world.respect.shared.viewmodel.report.list.ReportListViewModel import world.respect.shared.viewmodel.report.list.ReportTemplateListViewModel import world.respect.sharedse.domain.account.authenticatepassword.AuthenticatePasswordUseCaseDbImpl import java.io.File import world.respect.shared.viewmodel.settings.SettingsViewModel import world.respect.shared.viewmodel.curriculum.mapping.list.CurriculumMappingListViewModel import world.respect.shared.viewmodel.curriculum.mapping.edit.CurriculumMappingEditViewModel import world.respect.shared.viewmodel.person.setusernameandpassword.CreateAccountSetPasswordViewModel import world.respect.shared.viewmodel.person.setusernameandpassword.CreateAccountSetUserNameViewModel import world.respect.shared.viewmodel.schooldirectory.edit.SchoolDirectoryEditViewModel import world.respect.shared.viewmodel.schooldirectory.list.SchoolDirectoryListViewModel import world.respect.shared.domain.sharelink.LaunchSendEmailUseCase import world.respect.shared.domain.sharelink.LaunchShareLinkUseCase import world.respect.shared.domain.sharelink.LaunchSendSmsUseCase import world.respect.shared.domain.sendinvite.LaunchSendSmsAndroid import world.respect.shared.domain.sendinvite.LaunchSendEmailAndroid import world.respect.shared.domain.sendinvite.LaunchShareLinkAndroid import world.respect.shared.domain.urltonavcommand.ResolveUrlToNavCommandUseCase import world.respect.shared.viewmodel.scanqrcode.ScanQRCodeViewModel import world.respect.shared.domain.navigation.deferreddeeplink.GetDeferredDeepLinkUseCaseAndroid import world.respect.shared.domain.navigation.onappstart.NavigateOnAppStartUseCase import world.respect.shared.domain.xapi.getxapilaunchurl.GetXapiLaunchUrlUseCase import world.respect.shared.domain.xapi.getxapilaunchurl.GetXapiLaunchUrlUseCaseAndroid import world.respect.shared.domain.xapi.xapinanohttpd.XapiNanoHttpdResourceProviderAndroid const val SHARED_PREF_SETTINGS_NAME = "respect_settings3_" const val TAG_TMP_DIR = "tmpDir" @DelicateCoroutinesApi val appKoinModule = module { single { Json { encodeDefaults = false ignoreUnknownKeys = true } } single { PhoneNumberUtil.createInstance(androidContext()) } single { IPhoneNumberUtilAndroid(phoneNumberUtil = get()) } single { XXStringHasherCommonJvm() } single { LaunchSendSmsAndroid(androidContext()) } single { LaunchSendEmailAndroid(androidContext()) } single(createdAtStart = true) { GetDeferredDeepLinkUseCaseAndroid( context = androidContext(), settings = get() ) } single { LaunchShareLinkAndroid(androidContext()) } single { XXHashUidNumberMapper(xxStringHasher = get()) } single { val cachePathProvider: CachePathsProvider = get() OkHttpClient.Builder() .dispatcher( Dispatcher().also { it.maxRequests = 30 it.maxRequestsPerHost = 10 } ) .addInterceptor( UstadCacheInterceptor( cache = get(), tmpDirProvider = { File(cachePathProvider().tmpWorkPath.toString()) }, logger = NapierLoggingAdapter(), json = get(), connectivityMonitor = ConnectivityMonitorAndroid(androidContext()), ) ) .build() } single { HttpClient(OkHttp) { install(ContentNegotiation) { json(json = get()) } engine { preconfigured = get() } } } viewModelOf(::OnboardingViewModel) viewModelOf(::AppsDetailViewModel) viewModelOf(::AppLauncherViewModel) viewModelOf(::EnterLinkViewModel) viewModelOf(::AppListViewModel) viewModelOf(::ClazzListViewModel) viewModelOf(::ClazzEditViewModel) viewModelOf(::ClazzDetailViewModel) viewModelOf(::LearningUnitListViewModel) viewModelOf(::LearningUnitDetailViewModel) viewModelOf(::ReportViewModel) viewModelOf(::AcknowledgementViewModel) viewModelOf(::EnterInviteCodeViewModel) viewModelOf(::LoginViewModel) viewModelOf(::AcceptInviteViewModel) viewModelOf(::SignupViewModel) viewModelOf(::TermsAndConditionViewModel) viewModelOf(::WaitingForApprovalViewModel) viewModelOf(::CreateAccountViewModel) viewModelOf(::GetStartedViewModel) viewModelOf(::PasskeyListViewModel) viewModelOf(::HowPasskeyWorksViewModel) viewModelOf(::OtherOptionsViewModel) viewModelOf(::OtherOptionsSignupViewModel) viewModelOf(::EnterPasswordSignupViewModel) viewModelOf(::AccountListViewModel) viewModelOf(::ManageAccountViewModel) viewModelOf(::PersonListViewModel) viewModelOf(::InvitePersonViewModel) viewModelOf(::CopyInviteCodeViewModel) viewModelOf(::PersonEditViewModel) viewModelOf(::PersonDetailViewModel) viewModelOf(::ReportDetailViewModel) viewModelOf(::ReportEditViewModel) viewModelOf(::ReportListViewModel) viewModelOf(::ReportTemplateListViewModel) viewModelOf(::IndicatorEditViewModel) viewModelOf(::ReportFilterEditViewModel) viewModelOf(::IndicatorListViewModel) viewModelOf(::IndicatorDetailViewModel) viewModelOf(::SettingsViewModel) viewModelOf(::ScanQRCodeViewModel) viewModelOf(::CurriculumMappingListViewModel) viewModelOf(::CurriculumMappingEditViewModel) viewModelOf(::CreateAccountSetUserNameViewModel) viewModelOf(::ChangePasswordViewModel) viewModelOf(::SchoolDirectoryListViewModel) viewModelOf(::SchoolDirectoryEditViewModel) viewModelOf(::AssignmentListViewModel) viewModelOf(::AssignmentEditViewModel) viewModelOf(::AssignmentDetailViewModel) viewModelOf(::EnrollmentListViewModel) viewModelOf(::EnrollmentEditViewModel) viewModelOf(::InviteQrViewModel) viewModelOf(::CreateAccountSetPasswordViewModel) single { GetOfflineStorageOptionsUseCaseAndroid( getAndroidSdCardDirUseCase = get() ) } single { GetAndroidSdCardDirUseCase( appContext = androidContext().applicationContext ) } single { GetOfflineStorageSettingUseCase( getOfflineStorageOptionsUseCase = get(), settings = get(), ) } single { CachePathsProviderAndroid( appContext = androidContext().applicationContext, getAndroidSdCardPathUseCase = get(), getOfflineStorageSettingUseCase = get(), ) } single { SharedPreferencesSettings( delegate = androidContext().getSharedPreferences( SHARED_PREF_SETTINGS_NAME, Context.MODE_PRIVATE ) ) } single { Room.databaseBuilder( androidContext().applicationContext, UstadCacheDb::class.java, UstadCacheBuilder.DEFAULT_DB_NAME ).addCallback(ClearNeighborsCallback()) .build() } single { UstadCacheBuilder( appContext = androidContext().applicationContext, storagePath = Path( File(androidContext().filesDir, "httpfiles").absolutePath ), sizeLimit = { 100_000_000L }, db = get(), ).build() } single { OkHttpWebViewClient( okHttpClient = get() ) } single(named(TAG_TMP_DIR)) { File(androidContext().applicationContext.cacheDir, "tmp").apply { mkdirs() } } single { RespectAccountManager( settings = get(), json = get(), tokenManager = get(), appDataSource = get(), ) } single { RespectTokenManager( settings = get(), json = get(), ) } single { ValidateUsernameUseCase() } single { FilterUsernameUseCase() } single { EncodeUserHandleUseCaseImpl() } single { CreatePublicKeyCredentialRequestOptionsJsonUseCase() } single { GetCredentialUseCaseAndroidImpl( json = get(), createPublicKeyCredentialRequestOptionsJsonUseCase = get() ) } single { VerifyDomainUseCaseImpl( context = androidApplication() ) } single { SavePasswordUseCaseAndroidImpl() } single { SchoolDirectoryDataSourceDb( respectAppDb = get(), xxStringHasher = get() ) } single { val appContext = androidContext().applicationContext Room.databaseBuilder( appContext, appContext.getDatabasePath("respect_3_app.db").absolutePath ).setDriver(BundledSQLiteDriver()) .addCallback(AddSchoolDirectoryCallback(xxStringHasher = get())) .addCommonMigrations() .build() } single { RespectAppDataSourceRepository( local = RespectAppDataSourceDb( respectAppDatabase = get(), json = get(), xxStringHasher = get(), ), remote = RespectAppDataSourceHttp( local = RespectAppDataSourceDb( respectAppDatabase = get(), json = get(), xxStringHasher = get(), ), httpClient = get(), ) ) } single { NavResultReturnerImpl() } single { VerifyPasskeyUseCase( httpClient = get(), json = get() ) } single { XXHasher64FactoryCommonJvm() } single { ExtendedDataSourceValidationHelperImpl( respectAppDb = get(), xxStringHasher = get(), xxHasher64Factory = get(), ) } single { SetClipboardStringUseCaseAndroid(androidContext().applicationContext) } single { LaunchCustomTabUseCaseAndroid(androidContext().applicationContext) } single { ShouldShowOnboardingUseCase(settings = get()) } single { GetUsageReportingEnabledUseCaseAndroid(androidContext()) } single { SetUsageReportingEnabledUseCaseAndroid(androidContext()) } single { GetDeviceInfoUseCaseAndroid(androidContext()) } single { CreatePasskeyUseCaseAndroidChannelHost() } factory { LoadAaguidJsonUseCaseAndroid( appContext = androidContext().applicationContext, json = get(), ) } factory { GetPasskeyProviderInfoUseCaseImpl( json = get(), loadAaguidJsonUseCase = get() ) } single { GetAppVersionInfoUseCaseAndroid( context = androidContext() ) } single { GetWarningsUseCaseAndroid() } single { EncryptPersonPasswordUseCaseImpl() } single { ValidatePasswordUseCase() } single { SnackBarFlowDispatcher() } single { get() } single { ResolveUrlToNavCommandUseCase() } single { InitDeepLinkUriProviderUseCaseAndroid() } single { get() } single { PhoneNumValidatorAndroid(iPhoneNumberUtil = get()) } single { OnClickPhoneNumberUseCaseAndroid(androidContext()) } single { PinPublicationPrepareUseCase( httpClient = get(), db = get(), cache = get(), enqueueRunDownloadJobUseCase = get(), ) } single { EnqueueRunDownloadJobUseCaseAndroid(androidContext()) } single { RunDownloadJobUseCaseImpl( okHttpClient = get(), db = get(), httpCache = get(), ) } single { GetDevModeEnabledUseCase(settings = get()) } single { SetDevModeEnabledUseCase(settings = get()) } single { UrlToCustomDeepLinkUseCase(customProtocol = androidApplication().packageName) } single { CustomDeepLinkToUrlUseCase(customProtocol = androidApplication().packageName) } single { BiometricAuthUseCaseAndroidImpl() } single { get() } single { NavigateOnAppStartUseCase( accountManager = get(), initDeepLinkUriProvider = get(), getDeferredDeepLinkUseCase = get(), customDeepLinkToUrlUseCase = get(), resolveUrlToNavCommandUseCase = get(), settings = get(), ) } single(createdAtStart = true) { XapiNanoHttpdApp( port = 0, json = get(), xapiResourceProvider = get(), ).also { nanoHttpdApp -> GlobalScope.launch(Dispatchers.IO) { nanoHttpdApp.start() Napier.i("NanoHttpdXapi started") } } } single { XapiNanoHttpdResourceProviderAndroid() } /** * The SchoolDirectoryEntry scope might be one instance per school url or one instance per account * per url. * * ScopeId is set as per SchoolDirectoryEntryScopeId * * If the upstream server provides a list of grants/permission rules then the school database * can be shared */ scope { scoped { GetTokenAndUserProfileWithCredentialUseCaseClient( schoolUrl = SchoolDirectoryEntryScopeId.parse(id).schoolUrl, httpClient = get(), getDeviceInfoUseCase = get(), ) } scoped { RespectSchoolPath( path = Path( File( androidContext().filesDir, SchoolDirectoryEntryScopeId.parse(id).schoolUrl.sanitizedForFilename() ).absolutePath ) ) } scoped { Room.databaseBuilder( androidContext(), "school_3_" + SchoolDirectoryEntryScopeId.parse(id).schoolUrl.sanitizedForFilename() ) .addCommonMigrations() .build() } scoped { SchoolPrimaryKeyGenerator( primaryKeyGenerator = PrimaryKeyGenerator(SchoolPrimaryKeyGenerator.TABLE_IDS) ) } scoped { RedeemInviteUseCaseClient( schoolUrl = SchoolDirectoryEntryScopeId.parse(id).schoolUrl, httpClient = get(), ) } scoped { GetInviteInfoUseCaseClient( schoolUrl = SchoolDirectoryEntryScopeId.parse(id).schoolUrl, schoolDirectoryEntryDataSource = get().schoolDirectoryEntryDataSource, httpClient = get(), ) } scoped { CreateInviteLinkUseCase( schoolUrl = SchoolDirectoryEntryScopeId.parse(id).schoolUrl, ) } scoped { UsernameSuggestionUseCaseClient( schoolUrl = SchoolDirectoryEntryScopeId.parse(id).schoolUrl, schoolDirectoryEntryDataSource = get().schoolDirectoryEntryDataSource, httpClient = get(), ) } scoped { CheckUsernameUniqueUseCaseClient( schoolUrl = SchoolDirectoryEntryScopeId.parse(id).schoolUrl, schoolDirectoryEntryDataSource = get().schoolDirectoryEntryDataSource, httpClient = get(), ) } scoped { CreatePasskeyUseCaseAndroidImpl( sender = get(), json = get(), createPublicKeyJsonUseCase = get(), schoolUrl = SchoolDirectoryEntryScopeId.parse(id).schoolUrl, uidNumberMapper = get(), getPasskeyProviderInfoUseCase = get(), ) } scoped { CreatePublicKeyCredentialCreationOptionsJsonUseCase( encodeUserHandleUseCase = get(), appName = Res.string.app_name, schoolUrl = SchoolDirectoryEntryScopeId.parse(id).schoolUrl ) } scoped { CheckPasskeySupportUseCaseAndroidImpl( verifyDomainUseCase = get(), schoolUrl = SchoolDirectoryEntryScopeId.parse(id).schoolUrl, respectAppDataSource = get(), ) } scoped { AuthenticatePasswordUseCaseDbImpl( schoolDb = get(), encryptPersonPasswordUseCase = get(), uidNumberMapper = get(), ) } scoped { ValidateQrCodeUseCase( schoolUrl = SchoolDirectoryEntryScopeId.parse(id).schoolUrl ) } scoped { NavigateOnAccountCreatedUseCase( schoolUrl = SchoolDirectoryEntryScopeId.parse(id).schoolUrl ) } } /** * ScopeId is set as per RespectAccountScopeId * * The RespectAccount scope will be linked to SchoolDirectoryEntry (the parent) scope. */ scope { /* Koin doesn't have an onScopeCreated kind of function or event listener. The * RespectAccount scope is linked ot the SchoolDirectoryEntry scope when * RespectAccountSchoolScopeLink is retrieved. RespectAccountSchoolScopeLink is a root * dependency that all dependencies on RespectAccountScope require. */ scoped { val accountScopeId = RespectAccountScopeId.parse(id) val schoolDirectoryScope = SchoolDirectoryEntryScopeId( schoolUrl = accountScopeId.schoolUrl, accountPrincipalId = null, ) linkTo( getKoin().getOrCreateScope( schoolDirectoryScope.scopeId ) ) RespectAccountSchoolScopeLink(accountScopeId.schoolUrl) } scoped { get().providerFor(id) } scoped { get() val accountScopeId = RespectAccountScopeId.parse(id) RemoteWriteQueueDbImpl( schoolDb = get(), account = AuthenticatedUserPrincipalId(accountScopeId.accountPrincipalId.guid), enqueueDrainRemoteWriteQueueUseCase = get(), ) } scoped { GetActivePersonPasskeysClient( schoolUrl = SchoolDirectoryEntryScopeId.parse(id).schoolUrl, httpClient = get(), ) } scoped { RevokePasskeyUseCaseClient( schoolUrl = SchoolDirectoryEntryScopeId.parse(id).schoolUrl, httpClient = get(), ) } scoped { EnqueueDrainRemoteWriteQueueUseCaseAndroidImpl( context = androidContext().applicationContext, scopeId = id, scopeClass = RespectAccount::class, ) } scoped { DrainRemoteWriteQueueUseCase( remoteWriteQueue = get(), dataSource = get(), ) } scoped { val accountScopeId = RespectAccountScopeId.parse(id) SchoolDataSourceDb( schoolDb = get(), uidNumberMapper = get(), authenticatedUser = AuthenticatedUserPrincipalId( accountScopeId.accountPrincipalId.guid ), checkPersonPermissionUseCase = get(), json = get(), defaultAppCatalogUrl = RespectBuildConfig.RESPECT_DEFAULT_APPLIST, schoolUrl = accountScopeId.schoolUrl, ) } scoped { val schoolUrl = get() val localDs = get() SchoolDataSourceRepository( local = localDs, remote = SchoolDataSourceHttp( schoolUrl = schoolUrl.url, schoolDirectoryEntryDataSource = get().schoolDirectoryEntryDataSource, httpClient = get(), tokenProvider = get(), validationHelper = get(), json = get(), defaultAppCatalogUrl = RespectBuildConfig.RESPECT_DEFAULT_APPLIST, opdsFeedValidationHelper = localDs.opdsFeedDataSource, opdsPublicationValidationHelper = localDs.opdsPublicationDataSource .publicationNetworkValidationHelper ), validationHelper = get(), remoteWriteQueue = get(), ) } scoped { ApproveOrDeclineInviteRequestUseCase( schoolDataSource = get(), updateClazzStudentXapiGroupUseCase = get(), ) } scoped { AddChildAccountUseCaseClient( schoolUrl = RespectAccountScopeId.parse(id).schoolUrl, authTokenProvider = get(), httpClient = get(), schoolDirectoryEntryDataSource = get().schoolDirectoryEntryDataSource, schoolDataSourceLocal = get(), ) } scoped { val accountScopeId = RespectAccountScopeId.parse(id) GetAuthenticatedPersonUseCase( authenticatedUserPrincipalId = AuthenticatedUserPrincipalId( accountScopeId.accountPrincipalId.guid ), schoolDb = get(), uidNumberMapper = get(), ) } scoped { val accountScopeId = RespectAccountScopeId.parse(id) CheckPersonPermissionUseCaseDbImpl( schoolDb = get(), authenticatedUser = AuthenticatedUserPrincipalId( accountScopeId.accountPrincipalId.guid ), uidNumberMapper = get(), ) } scoped { CheckSchoolPermissionsUseCase( schoolDataSource = get(), ) } scoped { val accountScopeId = RespectAccountScopeId.parse(id) PullSyncTrackerDbImpl( schoolDb = get(), authenticatedUser = AuthenticatedUserPrincipalId( accountScopeId.accountPrincipalId.guid ), uidNumberMapper = get(), ) } scoped { EnqueueRunPullSyncUseCaseAndroidImpl( context = androidApplication(), scopeId = id, scopeClass = RespectAccount::class, ) } scoped { RunPullSyncUseCase( pullSyncTracker = get(), schoolDataSource = get(), authenticatedUser = RespectAccountScopeId.parse(id).accountPrincipalId, ) } scoped { GetWritableRolesListUseCaseImpl() } scoped { CreateClassUseCase(dataSource = get()) } scoped { val accountScopeId = RespectAccountScopeId.parse(id) GetXapiLaunchUrlUseCaseAndroid( nanoHttpdApp = get(), schoolUrl = accountScopeId.schoolUrl, authenticatedUser = accountScopeId.accountPrincipalId, json = get(), accountManager = get(), ) } scoped { LaunchAppUseCaseAndroid( appContext = androidContext().applicationContext, getXapiLaunchUrlUseCase = get(), ) } scoped() { val accountScopeId = RespectAccountScopeId.parse(id) UpdateClazzStudentXapiGroupUseCase( schoolDataSource = get(), authenticatedUserPrincipalId = accountScopeId.accountPrincipalId, schoolUrl = accountScopeId.schoolUrl, ) } } single { MockRunReportUseCaseClientImpl() } single{ ValidateEmailUseCase() } single { CreateGraphFormatterUseCase() } }