refactor: Migrate from Dagger to Hilt (#143)

- Remove `Injectable` interface, use `@AndroidEntryPoint`
- Remove `DispatchingAndroidInjector`
- Remove `viewModelFactory`, use `@HiltViewModel`
- Create providers for the different DAOs, and inject those instead of
  `AppDatabase`
- Create provider for a database transaction, inject that instead of
  `AppDatabase`
- Update tests
This commit is contained in:
Nik Clayton 2023-10-07 19:30:11 +02:00 committed by GitHub
parent 1161875014
commit 38214648dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
126 changed files with 1791 additions and 1939 deletions

View File

@ -5,6 +5,7 @@ plugins {
alias(libs.plugins.kotlin.kapt)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.aboutlibraries)
alias(libs.plugins.hilt)
id "app.pachli.plugins.markdown2resource"
}
@ -172,8 +173,8 @@ dependencies {
implementation libs.bundles.autodispose
implementation libs.bundles.dagger
kapt libs.bundles.dagger.processors
implementation libs.hilt.android
kapt libs.hilt.compiler
implementation libs.sparkbutton
@ -202,10 +203,15 @@ dependencies {
testImplementation libs.androidx.work.testing
testImplementation libs.truth
testImplementation libs.turbine
testImplementation libs.androidx.test.core.ktx
testImplementation libs.hilt.android.testing
kaptTest libs.hilt.compiler
androidTestImplementation libs.espresso.core
androidTestImplementation libs.androidx.room.testing
androidTestImplementation libs.androidx.test.junit
androidTestImplementation libs.hilt.android.testing
androidTestImplementation libs.androidx.test.core.ktx
}
tasks.register("newLintBaseline") {

View File

@ -29,17 +29,6 @@
file="$GRADLE_USER_HOME/caches/modules-2/files-2.1/org.pageseeder.diffx/pso-diffx/1.1.1/b655ebc87588a857a4f3d88cf98bcefa87a6105b/pso-diffx-1.1.1.jar"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 24 (current min is 23): `java.lang.Iterable#forEach`"
errorLine1=" media.value.forEach { item ->"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/components/compose/ComposeViewModel.kt"
line="278"
column="21"/>
</issue>
<issue
id="OldTargetApi"
message="Not targeting the latest versions of Android; compatibility modes apply. Consider testing and updating this version. Consult the android.os.Build.VERSION_CODES javadoc for details."
@ -47,7 +36,7 @@
errorLine2=" ~~~~~~~~~~~~">
<location
file="build.gradle"
line="35"
line="36"
column="9"/>
</issue>
@ -795,7 +784,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/account/AccountActivity.kt"
line="484"
line="475"
column="9"/>
</issue>
@ -2038,7 +2027,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/AboutActivity.kt"
line="73"
line="74"
column="9"/>
</issue>
@ -2049,7 +2038,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/AboutActivity.kt"
line="74"
line="75"
column="9"/>
</issue>
@ -2060,7 +2049,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/AboutActivity.kt"
line="75"
line="76"
column="9"/>
</issue>
@ -2137,7 +2126,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/components/account/AccountActivity.kt"
line="372"
line="363"
column="29"/>
</issue>
@ -2148,7 +2137,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/components/account/AccountActivity.kt"
line="375"
line="366"
column="29"/>
</issue>
@ -2159,7 +2148,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/components/account/AccountActivity.kt"
line="381"
line="372"
column="21"/>
</issue>
@ -2170,7 +2159,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/components/account/AccountActivity.kt"
line="382"
line="373"
column="21"/>
</issue>
@ -2181,7 +2170,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/components/account/AccountActivity.kt"
line="384"
line="375"
column="21"/>
</issue>
@ -2192,7 +2181,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/components/account/AccountActivity.kt"
line="394"
line="385"
column="21"/>
</issue>
@ -2214,7 +2203,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/preference/AccountPreferencesFragment.kt"
line="306"
line="307"
column="29"/>
</issue>
@ -2225,7 +2214,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/preference/AccountPreferencesFragment.kt"
line="312"
line="313"
column="25"/>
</issue>
@ -2236,7 +2225,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/app/pachli/AccountsInListFragment.kt"
line="118"
line="114"
column="21"/>
</issue>
@ -2247,7 +2236,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/app/pachli/AccountsInListFragment.kt"
line="125"
line="121"
column="25"/>
</issue>
@ -2258,7 +2247,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/AccountsInListFragment.kt"
line="186"
line="182"
column="17"/>
</issue>
@ -2269,7 +2258,7 @@
errorLine2=" ~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/AccountsInListFragment.kt"
line="196"
line="192"
column="128"/>
</issue>
@ -2280,7 +2269,7 @@
errorLine2=" ~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/AccountsInListFragment.kt"
line="196"
line="192"
column="128"/>
</issue>
@ -2291,7 +2280,7 @@
errorLine2=" ~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/AccountsInListFragment.kt"
line="198"
line="194"
column="71"/>
</issue>
@ -2302,7 +2291,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/app/pachli/AccountsInListFragment.kt"
line="198"
line="194"
column="63"/>
</issue>
@ -2313,7 +2302,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/AccountsInListFragment.kt"
line="225"
line="221"
column="21"/>
</issue>
@ -2324,7 +2313,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/AccountsInListFragment.kt"
line="227"
line="223"
column="21"/>
</issue>
@ -2335,7 +2324,7 @@
errorLine2=" ~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/AccountsInListFragment.kt"
line="237"
line="233"
column="128"/>
</issue>
@ -2346,7 +2335,7 @@
errorLine2=" ~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/AccountsInListFragment.kt"
line="237"
line="233"
column="128"/>
</issue>
@ -2357,7 +2346,7 @@
errorLine2=" ~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/AccountsInListFragment.kt"
line="239"
line="235"
column="71"/>
</issue>
@ -2368,21 +2357,10 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/app/pachli/AccountsInListFragment.kt"
line="239"
line="235"
column="63"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `handleActivity` of class `AppInjector` requires synthetic accessor"
errorLine1=" handleActivity(activity)"
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/di/AppInjector.kt"
line="38"
column="21"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `handleCloseButton` of class `ComposeActivity` requires synthetic accessor"
@ -2390,7 +2368,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/compose/ComposeActivity.kt"
line="544"
line="540"
column="21"/>
</issue>
@ -2401,7 +2379,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/compose/ComposeActivity.kt"
line="553"
line="549"
column="17"/>
</issue>
@ -2412,7 +2390,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/compose/ComposeActivity.kt"
line="553"
line="549"
column="17"/>
</issue>
@ -2478,7 +2456,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/components/conversation/ConversationsFragment.kt"
line="143"
line="140"
column="25"/>
</issue>
@ -2489,7 +2467,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/components/conversation/ConversationsFragment.kt"
line="145"
line="142"
column="33"/>
</issue>
@ -2500,7 +2478,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/filters/EditFilterActivity.kt"
line="118"
line="116"
column="17"/>
</issue>
@ -2511,7 +2489,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/filters/EditFilterActivity.kt"
line="118"
line="116"
column="17"/>
</issue>
@ -2522,7 +2500,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/filters/EditFilterActivity.kt"
line="128"
line="126"
column="17"/>
</issue>
@ -2533,7 +2511,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/filters/EditFilterActivity.kt"
line="128"
line="126"
column="17"/>
</issue>
@ -2544,7 +2522,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/components/followedtags/FollowedTagsActivity.kt"
line="96"
line="94"
column="25"/>
</issue>
@ -2555,7 +2533,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/followedtags/FollowedTagsActivity.kt"
line="204"
line="202"
column="21"/>
</issue>
@ -2566,7 +2544,7 @@
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/instancemute/fragment/InstanceListFragment.kt"
line="57"
line="58"
column="21"/>
</issue>
@ -2808,7 +2786,7 @@
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/ListsActivity.kt"
line="279"
line="269"
column="21"/>
</issue>
@ -2819,7 +2797,7 @@
errorLine2=" ~~~~~~">
<location
file="src/main/java/app/pachli/ListsActivity.kt"
line="281"
line="271"
column="21"/>
</issue>
@ -2830,7 +2808,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/account/list/ListsForAccountFragment.kt"
line="178"
line="174"
column="21"/>
</issue>
@ -2841,7 +2819,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/account/list/ListsForAccountFragment.kt"
line="184"
line="180"
column="21"/>
</issue>
@ -2852,7 +2830,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/login/LoginActivity.kt"
line="153"
line="154"
column="22"/>
</issue>
@ -2863,7 +2841,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/components/login/LoginWebViewActivity.kt"
line="146"
line="142"
column="17"/>
</issue>
@ -2874,7 +2852,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/components/login/LoginWebViewActivity.kt"
line="146"
line="142"
column="17"/>
</issue>
@ -2885,7 +2863,7 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/login/LoginWebViewActivity.kt"
line="155"
line="151"
column="17"/>
</issue>
@ -2896,7 +2874,7 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/login/LoginWebViewActivity.kt"
line="155"
line="151"
column="17"/>
</issue>
@ -2907,7 +2885,7 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/login/LoginWebViewActivity.kt"
line="176"
line="172"
column="25"/>
</issue>
@ -2918,7 +2896,7 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/login/LoginWebViewActivity.kt"
line="176"
line="172"
column="25"/>
</issue>
@ -2929,7 +2907,7 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/login/LoginWebViewActivity.kt"
line="179"
line="175"
column="25"/>
</issue>
@ -2940,7 +2918,7 @@
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/login/LoginWebViewActivity.kt"
line="179"
line="175"
column="25"/>
</issue>
@ -2951,7 +2929,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="241"
line="238"
column="37"/>
</issue>
@ -2962,7 +2940,7 @@
errorLine2=" ~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="245"
line="242"
column="37"/>
</issue>
@ -2973,7 +2951,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="349"
line="346"
column="25"/>
</issue>
@ -2984,7 +2962,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="350"
line="347"
column="29"/>
</issue>
@ -2995,7 +2973,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="352"
line="349"
column="25"/>
</issue>
@ -3006,7 +2984,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="353"
line="350"
column="29"/>
</issue>
@ -3015,20 +2993,20 @@
message="Access to `private` method `primaryDrawerItem` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" primaryDrawerItem {"
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="562"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="565"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="568"
column="21"/>
</issue>
@ -3039,7 +3017,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="573"
line="570"
column="17"/>
</issue>
@ -3050,7 +3028,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="577"
line="574"
column="21"/>
</issue>
@ -3059,20 +3037,20 @@
message="Access to `private` method `primaryDrawerItem` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" primaryDrawerItem {"
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="579"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="582"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="585"
column="21"/>
</issue>
@ -3081,20 +3059,20 @@
message="Access to `private` method `primaryDrawerItem` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" primaryDrawerItem {"
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="587"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="590"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="593"
column="21"/>
</issue>
@ -3103,20 +3081,20 @@
message="Access to `private` method `primaryDrawerItem` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" primaryDrawerItem {"
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="595"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="598"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="601"
column="21"/>
</issue>
@ -3125,20 +3103,20 @@
message="Access to `private` method `primaryDrawerItem` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" primaryDrawerItem {"
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="602"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="605"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="608"
column="21"/>
</issue>
@ -3147,20 +3125,20 @@
message="Access to `private` method `primaryDrawerItem` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" primaryDrawerItem {"
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="610"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="613"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="616"
column="21"/>
</issue>
@ -3171,7 +3149,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="620"
line="617"
column="17"/>
</issue>
@ -3182,7 +3160,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="624"
line="621"
column="21"/>
</issue>
@ -3191,20 +3169,20 @@
message="Access to `private` method `secondaryDrawerItem` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" secondaryDrawerItem {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="630"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="633"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="636"
column="21"/>
</issue>
@ -3213,20 +3191,20 @@
message="Access to `private` method `secondaryDrawerItem` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" secondaryDrawerItem {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="638"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="641"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="644"
column="21"/>
</issue>
@ -3235,20 +3213,20 @@
message="Access to `private` method `secondaryDrawerItem` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" secondaryDrawerItem {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="646"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="649"
column="17"/>
</issue>
<issue
id="SyntheticAccessor"
message="Access to `private` method `setOnClick` of class `MainActivityKt` requires synthetic accessor"
errorLine1=" onClick = {"
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="652"
column="21"/>
</issue>
@ -3259,7 +3237,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="657"
line="654"
column="17"/>
</issue>
@ -3270,7 +3248,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="660"
line="657"
column="21"/>
</issue>
@ -3281,7 +3259,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="667"
line="664"
column="21"/>
</issue>
@ -3292,7 +3270,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="670"
line="667"
column="25"/>
</issue>
@ -3303,7 +3281,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="679"
line="676"
column="17"/>
</issue>
@ -3314,7 +3292,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="682"
line="679"
column="21"/>
</issue>
@ -3325,7 +3303,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="695"
line="692"
column="17"/>
</issue>
@ -3336,7 +3314,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="699"
line="696"
column="21"/>
</issue>
@ -3347,7 +3325,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="819"
line="816"
column="17"/>
</issue>
@ -3358,7 +3336,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="821"
line="818"
column="17"/>
</issue>
@ -3369,7 +3347,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/MainActivity.kt"
line="832"
line="829"
column="17"/>
</issue>
@ -3600,7 +3578,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/notifications/NotificationsFragment.kt"
line="173"
line="168"
column="43"/>
</issue>
@ -3611,7 +3589,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/fragment/SFragment.kt"
line="183"
line="182"
column="48"/>
</issue>
@ -3644,7 +3622,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/app/pachli/TabPreferenceActivity.kt"
line="93"
line="94"
column="13"/>
</issue>
@ -3655,7 +3633,7 @@
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/app/pachli/TabPreferenceActivity.kt"
line="142"
line="143"
column="21"/>
</issue>
@ -3666,7 +3644,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/TabPreferenceActivity.kt"
line="152"
line="153"
column="59"/>
</issue>
@ -3677,7 +3655,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/TabPreferenceActivity.kt"
line="152"
line="153"
column="59"/>
</issue>
@ -3688,7 +3666,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/app/pachli/components/timeline/TimelineFragment.kt"
line="180"
line="174"
column="47"/>
</issue>
@ -3743,7 +3721,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/ViewMediaActivity.kt"
line="129"
line="125"
column="21"/>
</issue>
@ -3754,7 +3732,7 @@
errorLine2=" ~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/ViewMediaActivity.kt"
line="129"
line="125"
column="45"/>
</issue>
@ -3765,7 +3743,7 @@
errorLine2=" ~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/ViewMediaActivity.kt"
line="129"
line="125"
column="45"/>
</issue>
@ -3776,7 +3754,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/ViewMediaActivity.kt"
line="159"
line="155"
column="45"/>
</issue>
@ -3787,7 +3765,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/ViewMediaActivity.kt"
line="204"
line="200"
column="25"/>
</issue>
@ -3798,7 +3776,7 @@
errorLine2=" ~~~~~~~">
<location
file="src/main/java/app/pachli/fragment/ViewVideoFragment.kt"
line="142"
line="143"
column="32"/>
</issue>
@ -3809,7 +3787,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/app/pachli/fragment/ViewVideoFragment.kt"
line="223"
line="224"
column="21"/>
</issue>

View File

@ -17,14 +17,15 @@ import androidx.annotation.StringRes
import androidx.lifecycle.lifecycleScope
import app.pachli.components.instanceinfo.InstanceInfoRepository
import app.pachli.databinding.ActivityAboutBinding
import app.pachli.di.Injectable
import app.pachli.util.NoUnderlineURLSpan
import app.pachli.util.hide
import app.pachli.util.show
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject
class AboutActivity : BottomSheetActivity(), Injectable {
@AndroidEntryPoint
class AboutActivity : BottomSheetActivity() {
@Inject
lateinit var instanceInfoRepository: InstanceInfoRepository

View File

@ -32,8 +32,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.ListAdapter
import app.pachli.databinding.FragmentAccountsInListBinding
import app.pachli.databinding.ItemFollowRequestBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.entity.TimelineAccount
import app.pachli.settings.PrefKeys
import app.pachli.util.BindingHolder
@ -46,17 +44,15 @@ import app.pachli.util.unsafeLazy
import app.pachli.util.viewBinding
import app.pachli.viewmodel.AccountsInListViewModel
import app.pachli.viewmodel.State
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject
private typealias AccountInfo = Pair<TimelineAccount, Boolean>
class AccountsInListFragment : DialogFragment(), Injectable {
@AndroidEntryPoint
class AccountsInListFragment : DialogFragment() {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: AccountsInListViewModel by viewModels { viewModelFactory }
private val viewModel: AccountsInListViewModel by viewModels()
private val binding by viewBinding(FragmentAccountsInListBinding::bind)
private lateinit var listId: String

View File

@ -57,14 +57,15 @@ import app.pachli.adapter.AccountSelectionAdapter;
import app.pachli.components.login.LoginActivity;
import app.pachli.db.AccountEntity;
import app.pachli.db.AccountManager;
import app.pachli.di.Injectable;
import app.pachli.interfaces.AccountSelectionListener;
import app.pachli.interfaces.PermissionRequester;
import app.pachli.settings.PrefKeys;
import app.pachli.util.EmbeddedFontFamily;
import app.pachli.util.ThemeUtils;
import dagger.hilt.android.AndroidEntryPoint;
public abstract class BaseActivity extends AppCompatActivity implements Injectable {
@AndroidEntryPoint
public abstract class BaseActivity extends AppCompatActivity {
private static final String TAG = "BaseActivity";
/** @noinspection NotNullFieldNotInitialized*/

View File

@ -37,8 +37,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import app.pachli.adapter.AccountFieldEditAdapter
import app.pachli.components.instanceinfo.InstanceInfoRepository
import app.pachli.databinding.ActivityEditProfileBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.util.Error
import app.pachli.util.Loading
import app.pachli.util.Success
@ -59,10 +57,11 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject
class EditProfileActivity : BaseActivity(), Injectable {
@AndroidEntryPoint
class EditProfileActivity : BaseActivity() {
companion object {
const val AVATAR_SIZE = 400
@ -70,10 +69,7 @@ class EditProfileActivity : BaseActivity(), Injectable {
const val HEADER_HEIGHT = 500
}
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: EditProfileViewModel by viewModels { viewModelFactory }
private val viewModel: EditProfileViewModel by viewModels()
private val binding by viewBinding(ActivityEditProfileBinding::inflate)

View File

@ -21,7 +21,9 @@ import android.os.Bundle
import androidx.fragment.app.commit
import app.pachli.databinding.ActivityLicenseBinding
import com.mikepenz.aboutlibraries.LibsBuilder
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class LicenseActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {

View File

@ -38,8 +38,6 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import app.pachli.databinding.ActivityListsBinding
import app.pachli.databinding.DialogListBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.entity.MastoList
import app.pachli.util.hide
import app.pachli.util.show
@ -59,20 +57,12 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject
class ListsActivity : BaseActivity(), Injectable, HasAndroidInjector {
@Inject
lateinit var viewModelFactory: ViewModelFactory
@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
private val viewModel: ListsViewModel by viewModels { viewModelFactory }
@AndroidEntryPoint
class ListsActivity : BaseActivity() {
private val viewModel: ListsViewModel by viewModels()
private val binding by viewBinding(ActivityListsBinding::inflate)
@ -292,8 +282,6 @@ class ListsActivity : BaseActivity(), Injectable, HasAndroidInjector {
}
}
override fun androidInjector() = dispatchingAndroidInjector
companion object {
fun newIntent(context: Context) = Intent(context, ListsActivity::class.java)
}

View File

@ -140,17 +140,14 @@ import com.mikepenz.materialdrawer.util.addItems
import com.mikepenz.materialdrawer.util.addItemsAtPosition
import com.mikepenz.materialdrawer.util.updateBadge
import com.mikepenz.materialdrawer.widget.AccountHeaderView
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import dagger.hilt.android.AndroidEntryPoint
import de.c1710.filemojicompat_ui.helpers.EMOJI_PREFERENCE
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.launch
import javax.inject.Inject
class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInjector, MenuProvider {
@Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any>
@AndroidEntryPoint
class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
@Inject
lateinit var eventHub: EventHub
@ -1098,8 +1095,6 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
override fun getActionButton() = binding.composeButton
override fun androidInjector() = androidInjector
companion object {
private const val TAG = "MainActivity" // logging tag
private const val DRAWER_ITEM_ADD_ACCOUNT: Long = -13

View File

@ -25,7 +25,6 @@ import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import app.pachli.components.notifications.NotificationHelper
import app.pachli.di.AppInjector
import app.pachli.settings.NEW_INSTALL_SCHEMA_VERSION
import app.pachli.settings.PrefKeys
import app.pachli.settings.PrefKeys.APP_THEME
@ -36,8 +35,7 @@ import app.pachli.util.setAppNightMode
import app.pachli.worker.PruneCacheWorker
import app.pachli.worker.WorkerFactory
import autodispose2.AutoDisposePlugins
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import dagger.hilt.android.HiltAndroidApp
import de.c1710.filemojicompat_defaults.DefaultEmojiPackList
import de.c1710.filemojicompat_ui.helpers.EmojiPackHelper
import de.c1710.filemojicompat_ui.helpers.EmojiPreference
@ -47,10 +45,8 @@ import java.security.Security
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class PachliApplication : Application(), HasAndroidInjector {
@Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any>
@HiltAndroidApp
class PachliApplication : Application() {
@Inject
lateinit var workerFactory: WorkerFactory
@ -77,8 +73,6 @@ class PachliApplication : Application(), HasAndroidInjector {
AutoDisposePlugins.setHideProxies(false) // a small performance optimization
AppInjector.init(this)
// Migrate shared preference keys and defaults from version to version.
val oldVersion = sharedPreferences.getInt(PrefKeys.SCHEMA_VERSION, NEW_INSTALL_SCHEMA_VERSION)
if (oldVersion != SCHEMA_VERSION) {
@ -120,8 +114,6 @@ class PachliApplication : Application(), HasAndroidInjector {
)
}
override fun androidInjector() = androidInjector
private fun upgradeSharedPreferences(oldVersion: Int, newVersion: Int) {
Log.d(TAG, "Upgrading shared preferences: $oldVersion -> $newVersion")
val editor = sharedPreferences.edit()

View File

@ -20,7 +20,9 @@ package app.pachli
import android.os.Bundle
import android.util.Base64
import app.pachli.databinding.ActivityPrivacyPolicyBinding
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class PrivacyPolicyActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

View File

@ -24,11 +24,12 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import app.pachli.components.login.LoginActivity
import app.pachli.db.AccountManager
import app.pachli.di.Injectable
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@SuppressLint("CustomSplashScreen")
class SplashActivity : AppCompatActivity(), Injectable {
@AndroidEntryPoint
class SplashActivity : AppCompatActivity() {
@Inject
lateinit var accountManager: AccountManager

View File

@ -37,8 +37,7 @@ import app.pachli.util.viewBinding
import at.connyduck.calladapter.networkresult.fold
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.snackbar.Snackbar
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import retrofit2.HttpException
import javax.inject.Inject
@ -47,11 +46,8 @@ import javax.inject.Inject
* Show a list of statuses of a particular type; containing a particular hashtag,
* the user's favourites, bookmarks, etc.
*/
class StatusListActivity : BottomSheetActivity(), AppBarLayoutHost, HasAndroidInjector {
@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
@AndroidEntryPoint
class StatusListActivity : BottomSheetActivity(), AppBarLayoutHost {
@Inject
lateinit var eventHub: EventHub
@ -336,8 +332,6 @@ class StatusListActivity : BottomSheetActivity(), AppBarLayoutHost, HasAndroidIn
return true
}
override fun androidInjector() = dispatchingAndroidInjector
companion object {
private const val EXTRA_KIND = "kind"
private const val TAG = "StatusListActivity"

View File

@ -44,7 +44,6 @@ import app.pachli.adapter.TabAdapter
import app.pachli.appstore.EventHub
import app.pachli.appstore.MainTabsChangedEvent
import app.pachli.databinding.ActivityTabPreferenceBinding
import app.pachli.di.Injectable
import app.pachli.entity.MastoList
import app.pachli.network.MastodonApi
import app.pachli.util.getDimension
@ -59,6 +58,7 @@ import com.google.android.material.divider.MaterialDividerItemDecoration
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.transition.MaterialArcMotion
import com.google.android.material.transition.MaterialContainerTransform
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.awaitCancellation
@ -67,7 +67,8 @@ import kotlinx.coroutines.launch
import java.util.regex.Pattern
import javax.inject.Inject
class TabPreferenceActivity : BaseActivity(), Injectable, ItemInteractionListener {
@AndroidEntryPoint
class TabPreferenceActivity : BaseActivity(), ItemInteractionListener {
@Inject
lateinit var mastodonApi: MastodonApi

View File

@ -61,8 +61,7 @@ import autodispose2.androidx.lifecycle.AndroidLifecycleScopeProvider
import autodispose2.autoDispose
import com.bumptech.glide.Glide
import com.bumptech.glide.request.FutureTarget
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import dagger.hilt.android.AndroidEntryPoint
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
@ -71,14 +70,11 @@ import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.IOException
import java.util.Locale
import javax.inject.Inject
typealias ToolbarVisibilityListener = (isVisible: Boolean) -> Unit
class ViewMediaActivity : BaseActivity(), HasAndroidInjector, ViewImageFragment.PhotoActionsListener, ViewVideoFragment.VideoActionsListener {
@Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any>
@AndroidEntryPoint
class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener, ViewVideoFragment.VideoActionsListener {
private val binding by viewBinding(ActivityViewMediaBinding::inflate)
val toolbar: View
@ -351,8 +347,6 @@ class ViewMediaActivity : BaseActivity(), HasAndroidInjector, ViewImageFragment.
shareFile(file, mimeType)
}
override fun androidInjector() = androidInjector
companion object {
private const val EXTRA_ATTACHMENTS = "attachments"
private const val EXTRA_ATTACHMENT_INDEX = "index"

View File

@ -1,7 +1,7 @@
package app.pachli.appstore
import app.pachli.db.AccountManager
import app.pachli.db.AppDatabase
import app.pachli.db.TimelineDao
import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -13,15 +13,12 @@ import javax.inject.Inject
class CacheUpdater @Inject constructor(
eventHub: EventHub,
accountManager: AccountManager,
appDatabase: AppDatabase,
timelineDao: TimelineDao,
gson: Gson,
) {
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
init {
val timelineDao = appDatabase.timelineDao()
scope.launch {
eventHub.events.collect { event ->
val accountId = accountManager.activeAccount?.id ?: return@collect

View File

@ -58,7 +58,6 @@ import app.pachli.components.report.ReportActivity
import app.pachli.databinding.ActivityAccountBinding
import app.pachli.db.AccountEntity
import app.pachli.db.DraftsAlert
import app.pachli.di.ViewModelFactory
import app.pachli.entity.Account
import app.pachli.entity.Relationship
import app.pachli.interfaces.AccountSelectionListener
@ -94,8 +93,7 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import dagger.hilt.android.AndroidEntryPoint
import java.text.NumberFormat
import java.text.ParseException
import java.text.SimpleDateFormat
@ -103,23 +101,16 @@ import java.util.Locale
import javax.inject.Inject
import kotlin.math.abs
@AndroidEntryPoint
class AccountActivity :
BottomSheetActivity(),
ActionButtonActivity,
MenuProvider,
HasAndroidInjector,
LinkListener {
@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
@Inject
lateinit var viewModelFactory: ViewModelFactory
@Inject
lateinit var draftsAlert: DraftsAlert
private val viewModel: AccountViewModel by viewModels { viewModelFactory }
private val viewModel: AccountViewModel by viewModels()
private val binding: ActivityAccountBinding by viewBinding(ActivityAccountBinding::inflate)
@ -1012,8 +1003,6 @@ class AccountActivity :
}
}
override fun androidInjector() = dispatchingAndroidInjector
companion object {
private const val KEY_ACCOUNT_ID = "id"

View File

@ -20,11 +20,13 @@ import app.pachli.util.Resource
import app.pachli.util.Success
import app.pachli.util.getDomain
import at.connyduck.calladapter.networkresult.fold
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class AccountViewModel @Inject constructor(
private val mastodonApi: MastodonApi,
private val eventHub: EventHub,

View File

@ -30,24 +30,20 @@ import androidx.recyclerview.widget.ListAdapter
import app.pachli.R
import app.pachli.databinding.FragmentListsForAccountBinding
import app.pachli.databinding.ItemAddOrRemoveFromListBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.util.BindingHolder
import app.pachli.util.hide
import app.pachli.util.show
import app.pachli.util.viewBinding
import app.pachli.util.visible
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
class ListsForAccountFragment : DialogFragment(), Injectable {
@AndroidEntryPoint
class ListsForAccountFragment : DialogFragment() {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: ListsForAccountViewModel by viewModels { viewModelFactory }
private val viewModel: ListsForAccountViewModel by viewModels()
private val binding by viewBinding(FragmentListsForAccountBinding::bind)
private val adapter = Adapter()

View File

@ -24,6 +24,7 @@ import at.connyduck.calladapter.networkresult.getOrThrow
import at.connyduck.calladapter.networkresult.onFailure
import at.connyduck.calladapter.networkresult.onSuccess
import at.connyduck.calladapter.networkresult.runCatching
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
@ -50,6 +51,7 @@ data class ActionError(
}
@OptIn(ExperimentalCoroutinesApi::class)
@HiltViewModel
class ListsForAccountViewModel @Inject constructor(
private val mastodonApi: MastodonApi,
) : ViewModel() {

View File

@ -34,8 +34,6 @@ import app.pachli.R
import app.pachli.ViewMediaActivity
import app.pachli.databinding.FragmentTimelineBinding
import app.pachli.db.AccountManager
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.entity.Attachment
import app.pachli.interfaces.RefreshableFragment
import app.pachli.settings.PrefKeys
@ -49,6 +47,7 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
@ -56,21 +55,18 @@ import javax.inject.Inject
/**
* Fragment with multiple columns of media previews for the specified account.
*/
@AndroidEntryPoint
class AccountMediaFragment :
Fragment(R.layout.fragment_timeline),
RefreshableFragment,
MenuProvider,
Injectable {
@Inject
lateinit var viewModelFactory: ViewModelFactory
MenuProvider {
@Inject
lateinit var accountManager: AccountManager
private val binding by viewBinding(FragmentTimelineBinding::bind)
private val viewModel: AccountMediaViewModel by viewModels { viewModelFactory }
private val viewModel: AccountMediaViewModel by viewModels()
private lateinit var adapter: AccountMediaGridAdapter

View File

@ -24,8 +24,10 @@ import androidx.paging.cachedIn
import app.pachli.db.AccountManager
import app.pachli.network.MastodonApi
import app.pachli.viewdata.AttachmentViewData
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class AccountMediaViewModel @Inject constructor(
accountManager: AccountManager,
api: MastodonApi,

View File

@ -25,15 +25,10 @@ import app.pachli.databinding.ActivityAccountListBinding
import app.pachli.interfaces.AppBarLayoutHost
import app.pachli.util.viewBinding
import com.google.android.material.appbar.AppBarLayout
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import javax.inject.Inject
class AccountListActivity : BottomSheetActivity(), AppBarLayoutHost, HasAndroidInjector {
@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class AccountListActivity : BottomSheetActivity(), AppBarLayoutHost {
private val binding: ActivityAccountListBinding by viewBinding(ActivityAccountListBinding::inflate)
override val appBarLayout: AppBarLayout
@ -76,8 +71,6 @@ class AccountListActivity : BottomSheetActivity(), AppBarLayoutHost, HasAndroidI
}
}
override fun androidInjector() = dispatchingAndroidInjector
companion object {
private const val EXTRA_TYPE = "type"
private const val EXTRA_ID = "id"

View File

@ -40,7 +40,6 @@ import app.pachli.components.accountlist.adapter.FollowRequestsHeaderAdapter
import app.pachli.components.accountlist.adapter.MutesAdapter
import app.pachli.databinding.FragmentAccountListBinding
import app.pachli.db.AccountManager
import app.pachli.di.Injectable
import app.pachli.entity.Relationship
import app.pachli.entity.TimelineAccount
import app.pachli.interfaces.AccountActionListener
@ -57,16 +56,17 @@ import at.connyduck.calladapter.networkresult.fold
import com.google.android.material.color.MaterialColors
import com.google.android.material.divider.MaterialDividerItemDecoration
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import retrofit2.Response
import java.io.IOException
import javax.inject.Inject
@AndroidEntryPoint
class AccountListFragment :
Fragment(R.layout.fragment_account_list),
AccountActionListener,
LinkListener,
Injectable {
LinkListener {
@Inject
lateinit var api: MastodonApi

View File

@ -34,8 +34,6 @@ import app.pachli.StatusListActivity
import app.pachli.adapter.EmojiAdapter
import app.pachli.adapter.OnEmojiSelectedListener
import app.pachli.databinding.ActivityAnnouncementsBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.settings.PrefKeys
import app.pachli.util.Error
import app.pachli.util.Loading
@ -51,19 +49,16 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import javax.inject.Inject
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class AnnouncementsActivity :
BottomSheetActivity(),
AnnouncementActionListener,
OnEmojiSelectedListener,
MenuProvider,
Injectable {
MenuProvider {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: AnnouncementsViewModel by viewModels { viewModelFactory }
private val viewModel: AnnouncementsViewModel by viewModels()
private val binding by viewBinding(ActivityAnnouncementsBinding::inflate)

View File

@ -31,9 +31,11 @@ import app.pachli.util.Loading
import app.pachli.util.Resource
import app.pachli.util.Success
import at.connyduck.calladapter.networkresult.fold
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class AnnouncementsViewModel @Inject constructor(
private val instanceInfoRepo: InstanceInfoRepository,
private val mastodonApi: MastodonApi,

View File

@ -81,8 +81,6 @@ import app.pachli.components.instanceinfo.InstanceInfoRepository
import app.pachli.databinding.ActivityComposeBinding
import app.pachli.db.AccountEntity
import app.pachli.db.DraftAttachment
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.entity.Attachment
import app.pachli.entity.Emoji
import app.pachli.entity.NewPoll
@ -115,6 +113,7 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
@ -124,23 +123,20 @@ import java.io.File
import java.io.IOException
import java.text.DecimalFormat
import java.util.Locale
import javax.inject.Inject
import kotlin.math.max
import kotlin.math.min
@AndroidEntryPoint
class ComposeActivity :
BaseActivity(),
ComposeOptionsListener,
ComposeAutoCompleteAdapter.AutocompletionProvider,
OnEmojiSelectedListener,
Injectable,
OnReceiveContentListener,
ComposeScheduleView.OnTimeSetListener,
CaptionDialog.Listener {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private lateinit var composeOptionsBehavior: BottomSheetBehavior<*>
private lateinit var addMediaBehavior: BottomSheetBehavior<*>
private lateinit var emojiBehavior: BottomSheetBehavior<*>
@ -157,7 +153,7 @@ class ComposeActivity :
var maximumTootCharacters = InstanceInfoRepository.DEFAULT_CHARACTER_LIMIT
var charactersReservedPerUrl = InstanceInfoRepository.DEFAULT_CHARACTERS_RESERVED_PER_URL
private val viewModel: ComposeViewModel by viewModels { viewModelFactory }
private val viewModel: ComposeViewModel by viewModels()
private val binding by viewBinding(ActivityComposeBinding::inflate)

View File

@ -38,6 +38,7 @@ import app.pachli.service.ServiceClient
import app.pachli.service.StatusToSend
import app.pachli.util.randomAlphanumericString
import at.connyduck.calladapter.networkresult.fold
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
@ -52,6 +53,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
@HiltViewModel
class ComposeViewModel @Inject constructor(
private val api: MastodonApi,
private val accountManager: AccountManager,

View File

@ -37,6 +37,7 @@ import app.pachli.util.getImageSquarePixels
import app.pachli.util.getMediaSize
import app.pachli.util.getServerErrorMessage
import app.pachli.util.randomAlphanumericString
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
@ -98,7 +99,7 @@ class UploadServerError(val errorMessage: String) : Exception()
@Singleton
class MediaUploader @Inject constructor(
private val context: Context,
@ApplicationContext private val context: Context,
private val mediaUploadApi: MediaUploadApi,
) {

View File

@ -41,8 +41,6 @@ import app.pachli.appstore.EventHub
import app.pachli.appstore.PreferenceChangedEvent
import app.pachli.components.account.AccountActivity
import app.pachli.databinding.FragmentTimelineBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.fragment.SFragment
import app.pachli.interfaces.ActionButtonActivity
import app.pachli.interfaces.ReselectableFragment
@ -61,6 +59,7 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
@ -68,20 +67,18 @@ import javax.inject.Inject
import kotlin.time.DurationUnit
import kotlin.time.toDuration
@AndroidEntryPoint
class ConversationsFragment :
SFragment(),
StatusActionListener,
Injectable,
ReselectableFragment,
MenuProvider {
@Inject
lateinit var viewModelFactory: ViewModelFactory
@Inject
lateinit var eventHub: EventHub
private val viewModel: ConversationsViewModel by viewModels { viewModelFactory }
private val viewModel: ConversationsViewModel by viewModels()
private val binding by viewBinding(FragmentTimelineBinding::bind)

View File

@ -4,9 +4,9 @@ import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import app.pachli.db.AccountManager
import app.pachli.db.AppDatabase
import app.pachli.db.ConversationsDao
import app.pachli.di.TransactionProvider
import app.pachli.network.MastodonApi
import app.pachli.util.HttpHeaderLink
import retrofit2.HttpException
@ -14,7 +14,8 @@ import retrofit2.HttpException
@OptIn(ExperimentalPagingApi::class)
class ConversationsRemoteMediator(
private val api: MastodonApi,
private val db: AppDatabase,
private val transactionProvider: TransactionProvider,
private val conversationsDao: ConversationsDao,
accountManager: AccountManager,
) : RemoteMediator<Int, ConversationEntity>() {
@ -45,16 +46,16 @@ class ConversationsRemoteMediator(
return MediatorResult.Error(HttpException(conversationsResponse))
}
db.withTransaction {
transactionProvider {
if (loadType == LoadType.REFRESH) {
db.conversationDao().deleteForAccount(activeAccount.id)
conversationsDao.deleteForAccount(activeAccount.id)
}
val linkHeader = conversationsResponse.headers()["Link"]
val links = HttpHeaderLink.parse(linkHeader)
nextKey = HttpHeaderLink.findByRelationType(links, "next")?.uri?.getQueryParameter("max_id")
db.conversationDao().insert(
conversationsDao.insert(
conversations
.filterNot { it.lastStatus == null }
.map { conversation ->

View File

@ -24,18 +24,22 @@ import androidx.paging.PagingConfig
import androidx.paging.cachedIn
import androidx.paging.map
import app.pachli.db.AccountManager
import app.pachli.db.AppDatabase
import app.pachli.db.ConversationsDao
import app.pachli.di.TransactionProvider
import app.pachli.network.MastodonApi
import app.pachli.usecase.TimelineCases
import app.pachli.util.EmptyPagingSource
import at.connyduck.calladapter.networkresult.fold
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class ConversationsViewModel @Inject constructor(
private val timelineCases: TimelineCases,
private val database: AppDatabase,
transactionProvider: TransactionProvider,
private val conversationsDao: ConversationsDao,
private val accountManager: AccountManager,
private val api: MastodonApi,
) : ViewModel() {
@ -43,13 +47,18 @@ class ConversationsViewModel @Inject constructor(
@OptIn(ExperimentalPagingApi::class)
val conversationFlow = Pager(
config = PagingConfig(pageSize = 30),
remoteMediator = ConversationsRemoteMediator(api, database, accountManager),
remoteMediator = ConversationsRemoteMediator(
api,
transactionProvider,
conversationsDao,
accountManager,
),
pagingSourceFactory = {
val activeAccount = accountManager.activeAccount
if (activeAccount == null) {
EmptyPagingSource()
} else {
database.conversationDao().conversationsForAccount(activeAccount.id)
conversationsDao.conversationsForAccount(activeAccount.id)
}
},
)
@ -140,7 +149,7 @@ class ConversationsViewModel @Inject constructor(
try {
api.deleteConversation(conversationId = conversation.id)
database.conversationDao().delete(
conversationsDao.delete(
id = conversation.id,
accountId = accountManager.activeAccount!!.id,
)
@ -163,7 +172,7 @@ class ConversationsViewModel @Inject constructor(
muted = !(conversation.lastStatus.status.muted ?: false),
)
database.conversationDao().insert(newConversation)
conversationsDao.insert(newConversation)
} catch (e: Exception) {
Log.w(TAG, "failed to mute conversation", e)
}
@ -171,7 +180,7 @@ class ConversationsViewModel @Inject constructor(
}
private suspend fun saveConversationToDb(conversation: ConversationEntity) {
database.conversationDao().insert(conversation)
conversationsDao.insert(conversation)
}
companion object {

View File

@ -22,13 +22,14 @@ import android.webkit.MimeTypeMap
import androidx.core.content.FileProvider
import androidx.core.net.toUri
import app.pachli.BuildConfig
import app.pachli.db.AppDatabase
import app.pachli.db.DraftAttachment
import app.pachli.db.DraftDao
import app.pachli.db.DraftEntity
import app.pachli.entity.Attachment
import app.pachli.entity.NewPoll
import app.pachli.entity.Status
import app.pachli.util.copyToFile
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
@ -43,13 +44,10 @@ import java.util.Locale
import javax.inject.Inject
class DraftHelper @Inject constructor(
val context: Context,
@ApplicationContext val context: Context,
private val okHttpClient: OkHttpClient,
db: AppDatabase,
private val draftDao: DraftDao,
) {
private val draftDao = db.draftDao()
suspend fun saveDraft(
draftId: Int,
accountId: Long,

View File

@ -30,27 +30,25 @@ import app.pachli.components.compose.ComposeActivity
import app.pachli.databinding.ActivityDraftsBinding
import app.pachli.db.DraftEntity
import app.pachli.db.DraftsAlert
import app.pachli.di.ViewModelFactory
import app.pachli.util.parseAsMastodonHtml
import app.pachli.util.visible
import at.connyduck.calladapter.networkresult.fold
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.divider.MaterialDividerItemDecoration
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import retrofit2.HttpException
import javax.inject.Inject
@AndroidEntryPoint
class DraftsActivity : BaseActivity(), DraftActionListener {
@Inject
lateinit var viewModelFactory: ViewModelFactory
@Inject
lateinit var draftsAlert: DraftsAlert
private val viewModel: DraftsViewModel by viewModels { viewModelFactory }
private val viewModel: DraftsViewModel by viewModels()
private lateinit var binding: ActivityDraftsBinding
private lateinit var bottomSheet: BottomSheetBehavior<LinearLayout>

View File

@ -21,16 +21,18 @@ import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.cachedIn
import app.pachli.db.AccountManager
import app.pachli.db.AppDatabase
import app.pachli.db.DraftDao
import app.pachli.db.DraftEntity
import app.pachli.entity.Status
import app.pachli.network.MastodonApi
import at.connyduck.calladapter.networkresult.NetworkResult
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class DraftsViewModel @Inject constructor(
val database: AppDatabase,
private val draftDao: DraftDao,
val accountManager: AccountManager,
val api: MastodonApi,
private val draftHelper: DraftHelper,
@ -38,7 +40,7 @@ class DraftsViewModel @Inject constructor(
val drafts = Pager(
config = PagingConfig(pageSize = 20),
pagingSourceFactory = { database.draftDao().draftsPagingSource(accountManager.activeAccount?.id!!) },
pagingSourceFactory = { draftDao.draftsPagingSource(accountManager.activeAccount?.id!!) },
).flow
.cachedIn(viewModelScope)
@ -48,14 +50,14 @@ class DraftsViewModel @Inject constructor(
// this does not immediately delete media files to avoid unnecessary file operations
// in case the user decides to restore the draft
viewModelScope.launch {
database.draftDao().delete(draft.id)
draftDao.delete(draft.id)
deletedDrafts.add(draft)
}
}
fun restoreDraft(draft: DraftEntity) {
viewModelScope.launch {
database.draftDao().insertOrReplace(draft)
draftDao.insertOrReplace(draft)
deletedDrafts.remove(draft)
}
}

View File

@ -17,7 +17,6 @@ import app.pachli.R
import app.pachli.appstore.EventHub
import app.pachli.databinding.ActivityEditFilterBinding
import app.pachli.databinding.DialogFilterBinding
import app.pachli.di.ViewModelFactory
import app.pachli.entity.Filter
import app.pachli.entity.FilterKeyword
import app.pachli.network.MastodonApi
@ -27,11 +26,13 @@ import at.connyduck.calladapter.networkresult.fold
import com.google.android.material.chip.Chip
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.switchmaterial.SwitchMaterial
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import retrofit2.HttpException
import java.util.Date
import javax.inject.Inject
@AndroidEntryPoint
class EditFilterActivity : BaseActivity() {
@Inject
lateinit var api: MastodonApi
@ -39,11 +40,8 @@ class EditFilterActivity : BaseActivity() {
@Inject
lateinit var eventHub: EventHub
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val binding by viewBinding(ActivityEditFilterBinding::inflate)
private val viewModel: EditFilterViewModel by viewModels { viewModelFactory }
private val viewModel: EditFilterViewModel by viewModels()
private lateinit var filter: Filter
private var originalFilter: Filter? = null

View File

@ -8,11 +8,13 @@ import app.pachli.entity.Filter
import app.pachli.entity.FilterKeyword
import app.pachli.network.MastodonApi
import at.connyduck.calladapter.networkresult.fold
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.withContext
import retrofit2.HttpException
import javax.inject.Inject
@HiltViewModel
class EditFilterViewModel @Inject constructor(val api: MastodonApi, val eventHub: EventHub) : ViewModel() {
private var originalFilter: Filter? = null
val title = MutableStateFlow("")

View File

@ -8,22 +8,20 @@ import androidx.lifecycle.lifecycleScope
import app.pachli.BaseActivity
import app.pachli.R
import app.pachli.databinding.ActivityFiltersBinding
import app.pachli.di.ViewModelFactory
import app.pachli.entity.Filter
import app.pachli.util.hide
import app.pachli.util.show
import app.pachli.util.viewBinding
import app.pachli.util.visible
import com.google.android.material.color.MaterialColors
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class FiltersActivity : BaseActivity(), FiltersListener {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val binding by viewBinding(ActivityFiltersBinding::inflate)
private val viewModel: FiltersViewModel by viewModels { viewModelFactory }
private val viewModel: FiltersViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

View File

@ -10,12 +10,14 @@ import app.pachli.entity.FilterV1
import app.pachli.network.MastodonApi
import at.connyduck.calladapter.networkresult.fold
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import retrofit2.HttpException
import javax.inject.Inject
@HiltViewModel
class FiltersViewModel @Inject constructor(
private val api: MastodonApi,
private val eventHub: EventHub,

View File

@ -18,7 +18,6 @@ import app.pachli.BaseActivity
import app.pachli.R
import app.pachli.components.compose.ComposeAutoCompleteAdapter
import app.pachli.databinding.ActivityFollowedTagsBinding
import app.pachli.di.ViewModelFactory
import app.pachli.interfaces.HashtagActionListener
import app.pachli.network.MastodonApi
import app.pachli.settings.PrefKeys
@ -29,10 +28,12 @@ import app.pachli.util.visible
import at.connyduck.calladapter.networkresult.fold
import com.google.android.material.divider.MaterialDividerItemDecoration
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class FollowedTagsActivity :
BaseActivity(),
HashtagActionListener,
@ -40,14 +41,11 @@ class FollowedTagsActivity :
@Inject
lateinit var api: MastodonApi
@Inject
lateinit var viewModelFactory: ViewModelFactory
@Inject
lateinit var sharedPreferences: SharedPreferences
private val binding by viewBinding(ActivityFollowedTagsBinding::inflate)
private val viewModel: FollowedTagsViewModel by viewModels { viewModelFactory }
private val viewModel: FollowedTagsViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

View File

@ -9,15 +9,16 @@ import androidx.paging.PagingConfig
import androidx.paging.cachedIn
import app.pachli.components.compose.ComposeAutoCompleteAdapter
import app.pachli.components.search.SearchType
import app.pachli.di.Injectable
import app.pachli.entity.HashTag
import app.pachli.network.MastodonApi
import at.connyduck.calladapter.networkresult.fold
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class FollowedTagsViewModel @Inject constructor(
private val api: MastodonApi,
) : ViewModel(), Injectable {
) : ViewModel() {
val tags: MutableList<HashTag> = mutableListOf()
var nextKey: String? = null
var currentSource: FollowedTagsPagingSource? = null

View File

@ -17,8 +17,8 @@ package app.pachli.components.instanceinfo
import android.util.Log
import app.pachli.db.AccountManager
import app.pachli.db.AppDatabase
import app.pachli.db.EmojisEntity
import app.pachli.db.InstanceDao
import app.pachli.db.InstanceInfoEntity
import app.pachli.entity.Emoji
import app.pachli.network.MastodonApi
@ -31,11 +31,9 @@ import javax.inject.Inject
class InstanceInfoRepository @Inject constructor(
private val api: MastodonApi,
db: AppDatabase,
private val instanceDao: InstanceDao,
accountManager: AccountManager,
) {
private val dao = db.instanceDao()
private val instanceName = accountManager.activeAccount!!.domain
/**
@ -45,10 +43,10 @@ class InstanceInfoRepository @Inject constructor(
*/
suspend fun getEmojis(): List<Emoji> = withContext(Dispatchers.IO) {
api.getCustomEmojis()
.onSuccess { emojiList -> dao.upsert(EmojisEntity(instanceName, emojiList)) }
.onSuccess { emojiList -> instanceDao.upsert(EmojisEntity(instanceName, emojiList)) }
.getOrElse { throwable ->
Log.w(TAG, "failed to load custom emojis, falling back to cache", throwable)
dao.getEmojiInfo(instanceName)?.emojiList.orEmpty()
instanceDao.getEmojiInfo(instanceName)?.emojiList.orEmpty()
}
}
@ -78,12 +76,12 @@ class InstanceInfoRepository @Inject constructor(
maxFieldNameLength = instance.pleroma?.metadata?.fieldLimits?.nameLength,
maxFieldValueLength = instance.pleroma?.metadata?.fieldLimits?.valueLength,
)
dao.upsert(instanceEntity)
try { instanceDao.upsert(instanceEntity) } catch (_: Exception) { }
instanceEntity
},
{ throwable ->
Log.w(TAG, "failed to instance, falling back to cache and default values", throwable)
dao.getInstanceInfo(instanceName)
try { instanceDao.getInstanceInfo(instanceName) } catch (_: Exception) { null }
},
).let { instanceInfo: InstanceInfoEntity? ->
InstanceInfo(

View File

@ -5,15 +5,10 @@ import app.pachli.BaseActivity
import app.pachli.R
import app.pachli.components.instancemute.fragment.InstanceListFragment
import app.pachli.databinding.ActivityAccountListBinding
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import javax.inject.Inject
class InstanceListActivity : BaseActivity(), HasAndroidInjector {
@Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any>
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class InstanceListActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityAccountListBinding.inflate(layoutInflater)
@ -31,6 +26,4 @@ class InstanceListActivity : BaseActivity(), HasAndroidInjector {
.replace(R.id.fragment_container, InstanceListFragment())
.commit()
}
override fun androidInjector() = androidInjector
}

View File

@ -11,7 +11,6 @@ import app.pachli.R
import app.pachli.components.instancemute.adapter.DomainMutesAdapter
import app.pachli.components.instancemute.interfaces.InstanceActionListener
import app.pachli.databinding.FragmentInstanceListBinding
import app.pachli.di.Injectable
import app.pachli.network.MastodonApi
import app.pachli.util.HttpHeaderLink
import app.pachli.util.hide
@ -21,12 +20,14 @@ import app.pachli.view.EndlessOnScrollListener
import at.connyduck.calladapter.networkresult.fold
import com.google.android.material.divider.MaterialDividerItemDecoration
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class InstanceListFragment :
Fragment(R.layout.fragment_instance_list),
Injectable,
InstanceActionListener {
@Inject

View File

@ -32,7 +32,6 @@ import app.pachli.BuildConfig
import app.pachli.MainActivity
import app.pachli.R
import app.pachli.databinding.ActivityLoginBinding
import app.pachli.di.Injectable
import app.pachli.entity.AccessToken
import app.pachli.network.MastodonApi
import app.pachli.util.getNonNullString
@ -42,12 +41,14 @@ import app.pachli.util.shouldRickRoll
import app.pachli.util.viewBinding
import at.connyduck.calladapter.networkresult.fold
import com.bumptech.glide.Glide
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import okhttp3.HttpUrl
import javax.inject.Inject
/** Main login page, the first thing that users see. Has prompt for instance and login button. */
class LoginActivity : BaseActivity(), Injectable {
@AndroidEntryPoint
class LoginActivity : BaseActivity() {
@Inject
lateinit var mastodonApi: MastodonApi

View File

@ -40,14 +40,12 @@ import app.pachli.BaseActivity
import app.pachli.BuildConfig
import app.pachli.R
import app.pachli.databinding.ActivityLoginWebviewBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.util.hide
import app.pachli.util.viewBinding
import app.pachli.util.visible
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
import javax.inject.Inject
/** Contract for starting [LoginWebViewActivity]. */
class OauthLogin : ActivityResultContract<LoginData, LoginResult>() {
@ -103,13 +101,11 @@ sealed class LoginResult : Parcelable {
}
/** Activity to do Oauth process using WebView. */
class LoginWebViewActivity : BaseActivity(), Injectable {
@AndroidEntryPoint
class LoginWebViewActivity : BaseActivity() {
private val binding by viewBinding(ActivityLoginWebviewBinding::inflate)
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: LoginWebViewViewModel by viewModels { viewModelFactory }
private val viewModel: LoginWebViewViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

View File

@ -20,10 +20,12 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.pachli.network.MastodonApi
import at.connyduck.calladapter.networkresult.fold
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class LoginWebViewViewModel @Inject constructor(
private val api: MastodonApi,
) : ViewModel() {

View File

@ -29,6 +29,7 @@ import app.pachli.entity.Notification
import app.pachli.network.Links
import app.pachli.network.MastodonApi
import app.pachli.util.isLessThan
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.delay
import javax.inject.Inject
import kotlin.math.min
@ -46,7 +47,7 @@ import kotlin.time.Duration.Companion.milliseconds
class NotificationFetcher @Inject constructor(
private val mastodonApi: MastodonApi,
private val accountManager: AccountManager,
private val context: Context,
@ApplicationContext private val context: Context,
) {
suspend fun fetchAndShow() {
for (account in accountManager.getAllAccountsOrderedByActive()) {

View File

@ -47,8 +47,6 @@ import app.pachli.R
import app.pachli.adapter.StatusBaseViewHolder
import app.pachli.components.timeline.TimelineLoadStateAdapter
import app.pachli.databinding.FragmentTimelineNotificationsBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.entity.Filter
import app.pachli.entity.Notification
import app.pachli.entity.Status
@ -75,6 +73,7 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
@ -83,8 +82,8 @@ import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class NotificationsFragment :
SFragment(),
StatusActionListener,
@ -92,13 +91,9 @@ class NotificationsFragment :
AccountActionListener,
OnRefreshListener,
MenuProvider,
Injectable,
ReselectableFragment {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: NotificationsViewModel by viewModels { viewModelFactory }
private val viewModel: NotificationsViewModel by viewModels()
private val binding by viewBinding(FragmentTimelineNotificationsBinding::bind)

View File

@ -50,6 +50,7 @@ import app.pachli.util.throttleFirst
import app.pachli.viewdata.NotificationViewData
import app.pachli.viewdata.StatusViewData
import at.connyduck.calladapter.networkresult.getOrThrow
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
@ -289,6 +290,7 @@ sealed class UiError(
}
@OptIn(ExperimentalCoroutinesApi::class)
@HiltViewModel
class NotificationsViewModel @Inject constructor(
private val repository: NotificationsRepository,
private val preferences: SharedPreferences,

View File

@ -33,7 +33,6 @@ import app.pachli.components.instancemute.InstanceListActivity
import app.pachli.components.login.LoginActivity
import app.pachli.components.notifications.currentAccountNeedsMigration
import app.pachli.db.AccountManager
import app.pachli.di.Injectable
import app.pachli.entity.Account
import app.pachli.entity.Status
import app.pachli.network.MastodonApi
@ -52,12 +51,14 @@ import app.pachli.util.unsafeLazy
import com.google.android.material.snackbar.Snackbar
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import dagger.hilt.android.AndroidEntryPoint
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import javax.inject.Inject
class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
@AndroidEntryPoint
class AccountPreferencesFragment : PreferenceFragmentCompat() {
@Inject
lateinit var accountManager: AccountManager

View File

@ -21,14 +21,15 @@ import app.pachli.R
import app.pachli.components.notifications.NotificationHelper
import app.pachli.db.AccountEntity
import app.pachli.db.AccountManager
import app.pachli.di.Injectable
import app.pachli.settings.PrefKeys
import app.pachli.settings.makePreferenceScreen
import app.pachli.settings.preferenceCategory
import app.pachli.settings.switchPreference
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
class NotificationPreferencesFragment : PreferenceFragmentCompat(), Injectable {
@AndroidEntryPoint
class NotificationPreferencesFragment : PreferenceFragmentCompat() {
@Inject
lateinit var accountManager: AccountManager

View File

@ -38,23 +38,19 @@ import app.pachli.settings.PrefKeys.APP_THEME
import app.pachli.util.APP_THEME_DEFAULT
import app.pachli.util.getNonNullString
import app.pachli.util.setAppNightMode
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class PreferencesActivity :
BaseActivity(),
SharedPreferences.OnSharedPreferenceChangeListener,
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback,
HasAndroidInjector {
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
@Inject
lateinit var eventHub: EventHub
@Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any>
private val restartActivitiesOnBackPressedCallback = object : OnBackPressedCallback(false) {
override fun handleOnBackPressed() {
/* Switching themes won't actually change the theme of activities on the back stack.
@ -180,8 +176,6 @@ class PreferencesActivity :
overridePendingTransition(R.anim.fade_in, R.anim.fade_out)
}
override fun androidInjector() = androidInjector
companion object {
@Suppress("unused")
private const val TAG = "PreferencesActivity"

View File

@ -20,7 +20,6 @@ import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import app.pachli.R
import app.pachli.db.AccountManager
import app.pachli.di.Injectable
import app.pachli.entity.Notification
import app.pachli.settings.AppTheme
import app.pachli.settings.PrefKeys
@ -40,10 +39,12 @@ import app.pachli.util.unsafeLazy
import app.pachli.view.FontFamilyDialogFragment
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import dagger.hilt.android.AndroidEntryPoint
import de.c1710.filemojicompat_ui.views.picker.preference.EmojiPickerPreference
import javax.inject.Inject
class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
@AndroidEntryPoint
class PreferencesFragment : PreferenceFragmentCompat() {
@Inject
lateinit var accountManager: AccountManager

View File

@ -23,21 +23,12 @@ import app.pachli.BottomSheetActivity
import app.pachli.R
import app.pachli.components.report.adapter.ReportPagerAdapter
import app.pachli.databinding.ActivityReportBinding
import app.pachli.di.ViewModelFactory
import app.pachli.util.viewBinding
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import javax.inject.Inject
import dagger.hilt.android.AndroidEntryPoint
class ReportActivity : BottomSheetActivity(), HasAndroidInjector {
@Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any>
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: ReportViewModel by viewModels { viewModelFactory }
@AndroidEntryPoint
class ReportActivity : BottomSheetActivity() {
private val viewModel: ReportViewModel by viewModels()
private val binding by viewBinding(ActivityReportBinding::inflate)
@ -138,6 +129,4 @@ class ReportActivity : BottomSheetActivity(), HasAndroidInjector {
putExtra(STATUS_ID, statusId)
}
}
override fun androidInjector() = androidInjector
}

View File

@ -37,6 +37,7 @@ import app.pachli.util.Resource
import app.pachli.util.Success
import app.pachli.viewdata.StatusViewData
import at.connyduck.calladapter.networkresult.fold
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.flatMapLatest
@ -44,6 +45,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class ReportViewModel @Inject constructor(
private val mastodonApi: MastodonApi,
private val eventHub: EventHub,

View File

@ -22,7 +22,6 @@ import app.pachli.entity.Status
import app.pachli.network.MastodonApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.rx3.await
import kotlinx.coroutines.withContext
class StatusesPagingSource(

View File

@ -23,20 +23,16 @@ import app.pachli.R
import app.pachli.components.report.ReportViewModel
import app.pachli.components.report.Screen
import app.pachli.databinding.FragmentReportDoneBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.util.Loading
import app.pachli.util.hide
import app.pachli.util.show
import app.pachli.util.viewBinding
import javax.inject.Inject
import dagger.hilt.android.AndroidEntryPoint
class ReportDoneFragment : Fragment(R.layout.fragment_report_done), Injectable {
@AndroidEntryPoint
class ReportDoneFragment : Fragment(R.layout.fragment_report_done) {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: ReportViewModel by activityViewModels { viewModelFactory }
private val viewModel: ReportViewModel by activityViewModels()
private val binding by viewBinding(FragmentReportDoneBinding::bind)

View File

@ -24,8 +24,6 @@ import app.pachli.R
import app.pachli.components.report.ReportViewModel
import app.pachli.components.report.Screen
import app.pachli.databinding.FragmentReportNoteBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.util.Error
import app.pachli.util.Loading
import app.pachli.util.Success
@ -33,15 +31,13 @@ import app.pachli.util.hide
import app.pachli.util.show
import app.pachli.util.viewBinding
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import java.io.IOException
import javax.inject.Inject
class ReportNoteFragment : Fragment(R.layout.fragment_report_note), Injectable {
@AndroidEntryPoint
class ReportNoteFragment : Fragment(R.layout.fragment_report_note) {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: ReportViewModel by activityViewModels { viewModelFactory }
private val viewModel: ReportViewModel by activityViewModels()
private val binding by viewBinding(FragmentReportNoteBinding::bind)

View File

@ -42,8 +42,6 @@ import app.pachli.components.report.adapter.AdapterHandler
import app.pachli.components.report.adapter.StatusesAdapter
import app.pachli.databinding.FragmentReportStatusesBinding
import app.pachli.db.AccountManager
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.entity.Attachment
import app.pachli.entity.Status
import app.pachli.util.StatusDisplayOptions
@ -57,24 +55,22 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class ReportStatusesFragment :
Fragment(R.layout.fragment_report_statuses),
Injectable,
OnRefreshListener,
MenuProvider,
AdapterHandler {
@Inject
lateinit var viewModelFactory: ViewModelFactory
@Inject
lateinit var accountManager: AccountManager
private val viewModel: ReportViewModel by activityViewModels { viewModelFactory }
private val viewModel: ReportViewModel by activityViewModels()
private val binding by viewBinding(FragmentReportStatusesBinding::bind)

View File

@ -33,8 +33,6 @@ import app.pachli.appstore.EventHub
import app.pachli.appstore.StatusScheduledEvent
import app.pachli.components.compose.ComposeActivity
import app.pachli.databinding.ActivityScheduledStatusBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.entity.ScheduledStatus
import app.pachli.util.hide
import app.pachli.util.show
@ -45,23 +43,21 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class ScheduledStatusActivity :
BaseActivity(),
ScheduledStatusActionListener,
MenuProvider,
Injectable {
@Inject
lateinit var viewModelFactory: ViewModelFactory
MenuProvider {
@Inject
lateinit var eventHub: EventHub
private val viewModel: ScheduledStatusViewModel by viewModels { viewModelFactory }
private val viewModel: ScheduledStatusViewModel by viewModels()
private val binding by viewBinding(ActivityScheduledStatusBinding::inflate)

View File

@ -25,9 +25,11 @@ import app.pachli.appstore.EventHub
import app.pachli.entity.ScheduledStatus
import app.pachli.network.MastodonApi
import at.connyduck.calladapter.networkresult.fold
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class ScheduledStatusViewModel @Inject constructor(
val mastodonApi: MastodonApi,
val eventHub: EventHub,

View File

@ -30,24 +30,16 @@ import app.pachli.BottomSheetActivity
import app.pachli.R
import app.pachli.components.search.adapter.SearchPagerAdapter
import app.pachli.databinding.ActivitySearchBinding
import app.pachli.di.ViewModelFactory
import app.pachli.settings.PrefKeys
import app.pachli.util.reduceSwipeSensitivity
import app.pachli.util.unsafeLazy
import app.pachli.util.viewBinding
import com.google.android.material.tabs.TabLayoutMediator
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import javax.inject.Inject
import dagger.hilt.android.AndroidEntryPoint
class SearchActivity : BottomSheetActivity(), HasAndroidInjector, MenuProvider, SearchView.OnQueryTextListener {
@Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any>
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: SearchViewModel by viewModels { viewModelFactory }
@AndroidEntryPoint
class SearchActivity : BottomSheetActivity(), MenuProvider, SearchView.OnQueryTextListener {
private val viewModel: SearchViewModel by viewModels()
private val binding by viewBinding(ActivitySearchBinding::inflate)
@ -165,8 +157,6 @@ class SearchActivity : BottomSheetActivity(), HasAndroidInjector, MenuProvider,
return false
}
override fun androidInjector() = androidInjector
companion object {
const val TAG = "SearchActivity"
fun getIntent(context: Context) = Intent(context, SearchActivity::class.java)

View File

@ -32,11 +32,13 @@ import app.pachli.viewdata.StatusViewData
import at.connyduck.calladapter.networkresult.NetworkResult
import at.connyduck.calladapter.networkresult.fold
import at.connyduck.calladapter.networkresult.onFailure
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class SearchViewModel @Inject constructor(
mastodonApi: MastodonApi,
private val timelineCases: TimelineCases,

View File

@ -24,8 +24,10 @@ import app.pachli.components.search.adapter.SearchAccountsAdapter
import app.pachli.entity.TimelineAccount
import app.pachli.settings.PrefKeys
import com.google.android.material.divider.MaterialDividerItemDecoration
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.Flow
@AndroidEntryPoint
class SearchAccountsFragment : SearchFragment<TimelineAccount>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

View File

@ -22,8 +22,6 @@ import app.pachli.StatusListActivity
import app.pachli.components.account.AccountActivity
import app.pachli.components.search.SearchViewModel
import app.pachli.databinding.FragmentSearchBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.interfaces.LinkListener
import app.pachli.network.MastodonApi
import app.pachli.util.viewBinding
@ -42,17 +40,13 @@ import javax.inject.Inject
abstract class SearchFragment<T : Any> :
Fragment(R.layout.fragment_search),
LinkListener,
Injectable,
SwipeRefreshLayout.OnRefreshListener,
MenuProvider {
@Inject
lateinit var viewModelFactory: ViewModelFactory
@Inject
lateinit var mastodonApi: MastodonApi
protected val viewModel: SearchViewModel by activityViewModels { viewModelFactory }
protected val viewModel: SearchViewModel by activityViewModels()
protected val binding by viewBinding(FragmentSearchBinding::bind)

View File

@ -22,8 +22,10 @@ import androidx.paging.PagingDataAdapter
import app.pachli.components.search.adapter.SearchHashtagsAdapter
import app.pachli.entity.HashTag
import com.google.android.material.divider.MaterialDividerItemDecoration
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.Flow
@AndroidEntryPoint
class SearchHashtagsFragment : SearchFragment<HashTag>() {
override val data: Flow<PagingData<HashTag>>

View File

@ -59,10 +59,12 @@ import app.pachli.viewdata.StatusViewData
import at.connyduck.calladapter.networkresult.fold
import com.google.android.material.divider.MaterialDividerItemDecoration
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class SearchStatusesFragment : SearchFragment<StatusViewData>(), StatusActionListener {
@Inject
lateinit var accountManager: AccountManager

View File

@ -25,10 +25,12 @@ import androidx.paging.PagingConfig
import androidx.paging.PagingData
import app.pachli.components.timeline.viewmodel.CachedTimelineRemoteMediator
import app.pachli.db.AccountManager
import app.pachli.db.AppDatabase
import app.pachli.db.RemoteKeyDao
import app.pachli.db.StatusViewDataEntity
import app.pachli.db.TimelineDao
import app.pachli.db.TimelineStatusWithAccount
import app.pachli.di.ApplicationScope
import app.pachli.di.TransactionProvider
import app.pachli.network.MastodonApi
import app.pachli.util.EmptyPagingSource
import app.pachli.viewdata.StatusViewData
@ -49,7 +51,9 @@ import javax.inject.Inject
class CachedTimelineRepository @Inject constructor(
private val mastodonApi: MastodonApi,
private val accountManager: AccountManager,
private val appDatabase: AppDatabase,
private val transactionProvider: TransactionProvider,
val timelineDao: TimelineDao,
private val remoteKeyDao: RemoteKeyDao,
private val gson: Gson,
@ApplicationScope private val externalScope: CoroutineScope,
) {
@ -67,7 +71,7 @@ class CachedTimelineRepository @Inject constructor(
Log.d(TAG, "getStatusStream(): key: $initialKey")
factory = InvalidatingPagingSourceFactory {
activeAccount?.let { appDatabase.timelineDao().getStatuses(it.id) } ?: EmptyPagingSource()
activeAccount?.let { timelineDao.getStatuses(it.id) } ?: EmptyPagingSource()
}
val row = initialKey?.let { key ->
@ -77,7 +81,7 @@ class CachedTimelineRepository @Inject constructor(
// Instead, get all the status IDs for this account, in timeline order, and find the
// row index that contains the status. The row index is the correct initialKey.
activeAccount?.let { account ->
appDatabase.timelineDao().getStatusRowNumber(account.id)
timelineDao.getStatusRowNumber(account.id)
.indexOfFirst { it == key }.takeIf { it != -1 }
}
}
@ -92,7 +96,9 @@ class CachedTimelineRepository @Inject constructor(
mastodonApi,
accountManager,
factory!!,
appDatabase,
transactionProvider,
timelineDao,
remoteKeyDao,
gson,
),
pagingSourceFactory = factory!!,
@ -103,7 +109,7 @@ class CachedTimelineRepository @Inject constructor(
suspend fun invalidate() {
// Invalidating when no statuses have been loaded can cause empty timelines because it
// cancels the network load.
if (appDatabase.timelineDao().getStatusCount(activeAccount!!.id) < 1) {
if (timelineDao.getStatusCount(activeAccount!!.id) < 1) {
return
}
@ -111,7 +117,7 @@ class CachedTimelineRepository @Inject constructor(
}
suspend fun saveStatusViewData(statusViewData: StatusViewData) = externalScope.launch {
appDatabase.timelineDao().upsertStatusViewData(
timelineDao.upsertStatusViewData(
StatusViewDataEntity(
serverId = statusViewData.actionableId,
timelineUserId = activeAccount!!.id,
@ -126,34 +132,33 @@ class CachedTimelineRepository @Inject constructor(
* @return Map between statusIDs and any viewdata for them cached in the repository.
*/
suspend fun getStatusViewData(statusId: List<String>): Map<String, StatusViewDataEntity> {
return appDatabase.timelineDao().getStatusViewData(activeAccount!!.id, statusId)
return timelineDao.getStatusViewData(activeAccount!!.id, statusId)
}
/** Remove all statuses authored/boosted by the given account, for the active account */
suspend fun removeAllByAccountId(accountId: String) = externalScope.launch {
appDatabase.timelineDao().removeAllByUser(activeAccount!!.id, accountId)
timelineDao.removeAllByUser(activeAccount!!.id, accountId)
}.join()
/** Remove all statuses from the given instance, for the active account */
suspend fun removeAllByInstance(instance: String) = externalScope.launch {
appDatabase.timelineDao()
.deleteAllFromInstance(activeAccount!!.id, instance)
timelineDao.deleteAllFromInstance(activeAccount!!.id, instance)
}.join()
/** Clear the warning (remove the "filtered" setting) for the given status, for the active account */
suspend fun clearStatusWarning(statusId: String) = externalScope.launch {
appDatabase.timelineDao().clearWarning(activeAccount!!.id, statusId)
timelineDao.clearWarning(activeAccount!!.id, statusId)
}.join()
/** Remove all statuses and invalidate the pager, for the active account */
suspend fun clearAndReload() = externalScope.launch {
appDatabase.timelineDao().removeAll(activeAccount!!.id)
timelineDao.removeAll(activeAccount!!.id)
factory?.invalidate()
}.join()
suspend fun clearAndReloadFromNewest() = externalScope.launch {
appDatabase.timelineDao().removeAll(activeAccount!!.id)
appDatabase.remoteKeyDao().delete(activeAccount.id)
timelineDao.removeAll(activeAccount!!.id)
remoteKeyDao.delete(activeAccount.id)
invalidate()
}

View File

@ -28,8 +28,8 @@ import android.view.ViewGroup
import android.view.accessibility.AccessibilityManager
import androidx.core.content.ContextCompat
import androidx.core.view.MenuProvider
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.paging.LoadState
@ -51,8 +51,6 @@ import app.pachli.components.timeline.viewmodel.StatusActionSuccess
import app.pachli.components.timeline.viewmodel.TimelineViewModel
import app.pachli.components.timeline.viewmodel.UiSuccess
import app.pachli.databinding.FragmentTimelineBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.entity.Status
import app.pachli.fragment.SFragment
import app.pachli.interfaces.ActionButtonActivity
@ -68,7 +66,6 @@ import app.pachli.util.getDrawableRes
import app.pachli.util.getErrorString
import app.pachli.util.hide
import app.pachli.util.show
import app.pachli.util.unsafeLazy
import app.pachli.util.viewBinding
import app.pachli.util.visible
import app.pachli.util.withPresentationState
@ -82,6 +79,7 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
@ -90,26 +88,22 @@ import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
@AndroidEntryPoint
class TimelineFragment :
SFragment(),
OnRefreshListener,
StatusActionListener,
Injectable,
ReselectableFragment,
RefreshableFragment,
MenuProvider {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: TimelineViewModel by unsafeLazy {
private val viewModel: TimelineViewModel by lazy {
if (timelineKind == TimelineKind.Home) {
ViewModelProvider(this, viewModelFactory)[CachedTimelineViewModel::class.java]
viewModels<CachedTimelineViewModel>().value
} else {
ViewModelProvider(this, viewModelFactory)[NetworkTimelineViewModel::class.java]
viewModels<NetworkTimelineViewModel>().value
}
}

View File

@ -25,14 +25,15 @@ import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.Transaction
import androidx.room.withTransaction
import app.pachli.db.AccountManager
import app.pachli.db.AppDatabase
import app.pachli.db.RemoteKeyDao
import app.pachli.db.RemoteKeyEntity
import app.pachli.db.RemoteKeyKind
import app.pachli.db.TimelineAccountEntity
import app.pachli.db.TimelineDao
import app.pachli.db.TimelineStatusEntity
import app.pachli.db.TimelineStatusWithAccount
import app.pachli.di.TransactionProvider
import app.pachli.entity.Status
import app.pachli.network.Links
import app.pachli.network.MastodonApi
@ -50,12 +51,11 @@ class CachedTimelineRemoteMediator(
private val api: MastodonApi,
accountManager: AccountManager,
private val factory: InvalidatingPagingSourceFactory<Int, TimelineStatusWithAccount>,
private val db: AppDatabase,
private val transactionProvider: TransactionProvider,
private val timelineDao: TimelineDao,
private val remoteKeyDao: RemoteKeyDao,
private val gson: Gson,
) : RemoteMediator<Int, TimelineStatusWithAccount>() {
private val timelineDao = db.timelineDao()
private val remoteKeyDao = db.remoteKeyDao()
private val activeAccount = accountManager.activeAccount!!
override suspend fun load(
@ -79,24 +79,20 @@ class CachedTimelineRemoteMediator(
getInitialPage(statusId, state.config.pageSize)
}
LoadType.APPEND -> {
val rke = db.withTransaction {
remoteKeyDao.remoteKeyForKind(
val rke = remoteKeyDao.remoteKeyForKind(
activeAccount.id,
TIMELINE_ID,
RemoteKeyKind.NEXT,
)
} ?: return MediatorResult.Success(endOfPaginationReached = true)
) ?: return MediatorResult.Success(endOfPaginationReached = true)
Log.d(TAG, "Loading from remoteKey: $rke")
api.homeTimeline(maxId = rke.key, limit = state.config.pageSize)
}
LoadType.PREPEND -> {
val rke = db.withTransaction {
remoteKeyDao.remoteKeyForKind(
val rke = remoteKeyDao.remoteKeyForKind(
activeAccount.id,
TIMELINE_ID,
RemoteKeyKind.PREV,
)
} ?: return MediatorResult.Success(endOfPaginationReached = true)
) ?: return MediatorResult.Success(endOfPaginationReached = true)
Log.d(TAG, "Loading from remoteKey: $rke")
api.homeTimeline(minId = rke.key, limit = state.config.pageSize)
}
@ -119,7 +115,8 @@ class CachedTimelineRemoteMediator(
Log.d(TAG, " ${statuses.first().id}..${statuses.last().id}")
val links = Links.from(response.headers()["link"])
db.withTransaction {
transactionProvider {
when (loadType) {
LoadType.REFRESH -> {
remoteKeyDao.delete(activeAccount.id)

View File

@ -40,6 +40,7 @@ import app.pachli.settings.AccountPreferenceDataStore
import app.pachli.usecase.TimelineCases
import app.pachli.viewdata.StatusViewData
import com.google.gson.Gson
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
@ -51,6 +52,7 @@ import javax.inject.Inject
/**
* TimelineViewModel that caches all statuses in a local database
*/
@HiltViewModel
class CachedTimelineViewModel @Inject constructor(
private val repository: CachedTimelineRepository,
timelineCases: TimelineCases,

View File

@ -39,6 +39,7 @@ import app.pachli.network.FilterModel
import app.pachli.settings.AccountPreferenceDataStore
import app.pachli.usecase.TimelineCases
import app.pachli.viewdata.StatusViewData
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
@ -49,6 +50,7 @@ import javax.inject.Inject
/**
* TimelineViewModel that caches all statuses in an in-memory list
*/
@HiltViewModel
class NetworkTimelineViewModel @Inject constructor(
private val repository: NetworkTimelineRepository,
timelineCases: TimelineCases,

View File

@ -39,15 +39,10 @@ import app.pachli.util.reduceSwipeSensitivity
import app.pachli.util.viewBinding
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.tabs.TabLayoutMediator
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import javax.inject.Inject
class TrendingActivity : BottomSheetActivity(), AppBarLayoutHost, HasAndroidInjector, MenuProvider {
@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class TrendingActivity : BottomSheetActivity(), AppBarLayoutHost, MenuProvider {
private val binding: ActivityTrendingBinding by viewBinding(ActivityTrendingBinding::inflate)
override val appBarLayout: AppBarLayout
@ -92,8 +87,6 @@ class TrendingActivity : BottomSheetActivity(), AppBarLayoutHost, HasAndroidInje
return super.onOptionsItemSelected(menuItem)
}
override fun androidInjector() = dispatchingAndroidInjector
companion object {
fun getIntent(context: Context) = Intent(context, TrendingActivity::class.java)
}

View File

@ -39,8 +39,6 @@ import app.pachli.components.trending.viewmodel.InfallibleUiAction
import app.pachli.components.trending.viewmodel.LoadState
import app.pachli.components.trending.viewmodel.TrendingLinksViewModel
import app.pachli.databinding.FragmentTrendingLinksBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.interfaces.ActionButtonActivity
import app.pachli.interfaces.AppBarLayoutHost
import app.pachli.interfaces.RefreshableFragment
@ -55,23 +53,20 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import retrofit2.HttpException
import javax.inject.Inject
@AndroidEntryPoint
class TrendingLinksFragment :
Fragment(R.layout.fragment_trending_links),
OnRefreshListener,
Injectable,
ReselectableFragment,
RefreshableFragment,
MenuProvider {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: TrendingLinksViewModel by viewModels { viewModelFactory }
private val viewModel: TrendingLinksViewModel by viewModels()
private val binding by viewBinding(FragmentTrendingLinksBinding::bind)

View File

@ -42,8 +42,6 @@ import app.pachli.R
import app.pachli.StatusListActivity
import app.pachli.components.trending.viewmodel.TrendingTagsViewModel
import app.pachli.databinding.FragmentTrendingTagsBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.interfaces.ActionButtonActivity
import app.pachli.interfaces.AppBarLayoutHost
import app.pachli.interfaces.RefreshableFragment
@ -58,22 +56,19 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class TrendingTagsFragment :
Fragment(R.layout.fragment_trending_tags),
OnRefreshListener,
Injectable,
ReselectableFragment,
RefreshableFragment,
MenuProvider {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: TrendingTagsViewModel by viewModels { viewModelFactory }
private val viewModel: TrendingTagsViewModel by viewModels()
private val binding by viewBinding(FragmentTrendingTagsBinding::bind)

View File

@ -28,6 +28,7 @@ import app.pachli.entity.TrendsLink
import app.pachli.util.StatusDisplayOptions
import app.pachli.util.throttleFirst
import at.connyduck.calladapter.networkresult.fold
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
@ -54,6 +55,7 @@ sealed class LoadState {
data class Error(val throwable: Throwable) : LoadState()
}
@HiltViewModel
class TrendingLinksViewModel @Inject constructor(
private val repository: TrendingLinksRepository,
preferences: SharedPreferences,

View File

@ -27,6 +27,7 @@ import app.pachli.entity.start
import app.pachli.network.MastodonApi
import app.pachli.viewdata.TrendingViewData
import at.connyduck.calladapter.networkresult.fold
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@ -35,6 +36,7 @@ import kotlinx.coroutines.launch
import java.io.IOException
import javax.inject.Inject
@HiltViewModel
class TrendingTagsViewModel @Inject constructor(
private val mastodonApi: MastodonApi,
private val eventHub: EventHub,

View File

@ -23,17 +23,12 @@ import app.pachli.BottomSheetActivity
import app.pachli.R
import app.pachli.databinding.ActivityViewThreadBinding
import app.pachli.util.viewBinding
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import javax.inject.Inject
class ViewThreadActivity : BottomSheetActivity(), HasAndroidInjector {
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class ViewThreadActivity : BottomSheetActivity() {
private val binding by viewBinding(ActivityViewThreadBinding::inflate)
@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
@ -54,8 +49,6 @@ class ViewThreadActivity : BottomSheetActivity(), HasAndroidInjector {
}
}
override fun androidInjector() = dispatchingAndroidInjector
companion object {
fun startIntent(context: Context, id: String, url: String): Intent {

View File

@ -39,8 +39,6 @@ import app.pachli.components.accountlist.AccountListActivity
import app.pachli.components.accountlist.AccountListActivity.Companion.newIntent
import app.pachli.components.viewthread.edits.ViewEditsFragment
import app.pachli.databinding.FragmentViewThreadBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.fragment.SFragment
import app.pachli.interfaces.StatusActionListener
import app.pachli.util.ListStatusAccessibilityDelegate
@ -54,23 +52,20 @@ import app.pachli.viewdata.StatusViewData
import com.google.android.material.color.MaterialColors
import com.google.android.material.divider.MaterialDividerItemDecoration
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class ViewThreadFragment :
SFragment(),
OnRefreshListener,
StatusActionListener,
MenuProvider,
Injectable {
MenuProvider {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: ViewThreadViewModel by viewModels { viewModelFactory }
private val viewModel: ViewThreadViewModel by viewModels()
private val binding by viewBinding(FragmentViewThreadBinding::bind)

View File

@ -31,7 +31,7 @@ import app.pachli.components.timeline.CachedTimelineRepository
import app.pachli.components.timeline.util.ifExpected
import app.pachli.db.AccountEntity
import app.pachli.db.AccountManager
import app.pachli.db.AppDatabase
import app.pachli.db.TimelineDao
import app.pachli.entity.Filter
import app.pachli.entity.FilterV1
import app.pachli.entity.Status
@ -43,6 +43,7 @@ import at.connyduck.calladapter.networkresult.fold
import at.connyduck.calladapter.networkresult.getOrElse
import at.connyduck.calladapter.networkresult.getOrThrow
import com.google.gson.Gson
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.BufferOverflow
@ -54,13 +55,14 @@ import kotlinx.coroutines.launch
import retrofit2.HttpException
import javax.inject.Inject
@HiltViewModel
class ViewThreadViewModel @Inject constructor(
private val api: MastodonApi,
private val filterModel: FilterModel,
private val timelineCases: TimelineCases,
eventHub: EventHub,
accountManager: AccountManager,
private val db: AppDatabase,
private val timelineDao: TimelineDao,
private val gson: Gson,
private val repository: CachedTimelineRepository,
) : ViewModel() {
@ -110,7 +112,7 @@ class ViewThreadViewModel @Inject constructor(
viewModelScope.launch {
Log.d(TAG, "Finding status with: $id")
val contextCall = async { api.statusContext(id) }
val timelineStatusWithAccount = db.timelineDao().getStatus(id)
val timelineStatusWithAccount = timelineDao.getStatus(id)
var detailedStatus = if (timelineStatusWithAccount != null) {
Log.d(TAG, "Loaded status from local timeline")

View File

@ -35,8 +35,6 @@ import app.pachli.R
import app.pachli.StatusListActivity
import app.pachli.components.account.AccountActivity
import app.pachli.databinding.FragmentViewEditsBinding
import app.pachli.di.Injectable
import app.pachli.di.ViewModelFactory
import app.pachli.interfaces.LinkListener
import app.pachli.settings.PrefKeys
import app.pachli.util.emojify
@ -51,20 +49,17 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class ViewEditsFragment :
Fragment(R.layout.fragment_view_edits),
LinkListener,
OnRefreshListener,
MenuProvider,
Injectable {
MenuProvider {
@Inject
lateinit var viewModelFactory: ViewModelFactory
private val viewModel: ViewEditsViewModel by viewModels { viewModelFactory }
private val viewModel: ViewEditsViewModel by viewModels()
private val binding by viewBinding(FragmentViewEditsBinding::bind)

View File

@ -24,6 +24,7 @@ import app.pachli.components.viewthread.edits.PachliTagHandler.Companion.INSERTE
import app.pachli.entity.StatusEdit
import app.pachli.network.MastodonApi
import at.connyduck.calladapter.networkresult.getOrElse
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -45,6 +46,7 @@ import org.pageseeder.xmlwriter.XML.NamespaceAware
import org.pageseeder.xmlwriter.XMLStringWriter
import javax.inject.Inject
@HiltViewModel
class ViewEditsViewModel @Inject constructor(private val api: MastodonApi) : ViewModel() {
private val _uiState: MutableStateFlow<EditsUiState> = MutableStateFlow(EditsUiState.Initial)

View File

@ -33,7 +33,10 @@ import javax.inject.Singleton
private const val TAG = "AccountManager"
@Singleton
class AccountManager @Inject constructor(val db: AppDatabase) {
class AccountManager @Inject constructor(
private val accountDao: AccountDao,
private val remoteKeyDao: RemoteKeyDao,
) {
@Volatile
var activeAccount: AccountEntity? = null
@ -42,8 +45,6 @@ class AccountManager @Inject constructor(val db: AppDatabase) {
var accounts: MutableList<AccountEntity> = mutableListOf()
private set
private val accountDao: AccountDao = db.accountDao()
init {
accounts = accountDao.loadAll().toMutableList()
@ -128,7 +129,7 @@ class AccountManager @Inject constructor(val db: AppDatabase) {
accounts.remove(account)
accountDao.delete(account)
db.remoteKeyDao().delete(account.id)
remoteKeyDao.delete(account.id)
if (accounts.size > 0) {
accounts[0].isActive = true

View File

@ -37,10 +37,7 @@ import javax.inject.Singleton
private const val TAG = "DraftsAlert"
@Singleton
class DraftsAlert @Inject constructor(db: AppDatabase) {
// For tracking when a media upload fails in the service
private val draftDao: DraftDao = db.draftDao()
class DraftsAlert @Inject constructor(private val draftDao: DraftDao) {
@Inject
lateinit var accountManager: AccountManager

View File

@ -1,135 +0,0 @@
/* Copyright 2018 charlag
*
* This file is a part of Pachli.
*
* 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.
*
* Pachli 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 app.pachli.di
import app.pachli.AboutActivity
import app.pachli.BaseActivity
import app.pachli.EditProfileActivity
import app.pachli.LicenseActivity
import app.pachli.ListsActivity
import app.pachli.MainActivity
import app.pachli.PrivacyPolicyActivity
import app.pachli.SplashActivity
import app.pachli.StatusListActivity
import app.pachli.TabPreferenceActivity
import app.pachli.ViewMediaActivity
import app.pachli.components.account.AccountActivity
import app.pachli.components.accountlist.AccountListActivity
import app.pachli.components.announcements.AnnouncementsActivity
import app.pachli.components.compose.ComposeActivity
import app.pachli.components.drafts.DraftsActivity
import app.pachli.components.filters.EditFilterActivity
import app.pachli.components.filters.FiltersActivity
import app.pachli.components.followedtags.FollowedTagsActivity
import app.pachli.components.instancemute.InstanceListActivity
import app.pachli.components.login.LoginActivity
import app.pachli.components.login.LoginWebViewActivity
import app.pachli.components.preference.PreferencesActivity
import app.pachli.components.report.ReportActivity
import app.pachli.components.scheduled.ScheduledStatusActivity
import app.pachli.components.search.SearchActivity
import app.pachli.components.trending.TrendingActivity
import app.pachli.components.viewthread.ViewThreadActivity
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class ActivitiesModule {
@ContributesAndroidInjector
abstract fun contributesBaseActivity(): BaseActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesMainActivity(): MainActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesAccountActivity(): AccountActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesListsActivity(): ListsActivity
@ContributesAndroidInjector
abstract fun contributesComposeActivity(): ComposeActivity
@ContributesAndroidInjector
abstract fun contributesEditProfileActivity(): EditProfileActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesAccountListActivity(): AccountListActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesViewThreadActivity(): ViewThreadActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesStatusListActivity(): StatusListActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesSearchActivity(): SearchActivity
@ContributesAndroidInjector
abstract fun contributesAboutActivity(): AboutActivity
@ContributesAndroidInjector
abstract fun contributesLoginActivity(): LoginActivity
@ContributesAndroidInjector
abstract fun contributesLoginWebViewActivity(): LoginWebViewActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesPreferencesActivity(): PreferencesActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesViewMediaActivity(): ViewMediaActivity
@ContributesAndroidInjector
abstract fun contributesLicenseActivity(): LicenseActivity
@ContributesAndroidInjector
abstract fun contributesTabPreferenceActivity(): TabPreferenceActivity
@ContributesAndroidInjector
abstract fun contributesFiltersActivity(): FiltersActivity
@ContributesAndroidInjector
abstract fun contributesFollowedTagsActivity(): FollowedTagsActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesReportActivity(): ReportActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesInstanceListActivity(): InstanceListActivity
@ContributesAndroidInjector
abstract fun contributesScheduledStatusActivity(): ScheduledStatusActivity
@ContributesAndroidInjector
abstract fun contributesAnnouncementsActivity(): AnnouncementsActivity
@ContributesAndroidInjector
abstract fun contributesDraftActivity(): DraftsActivity
@ContributesAndroidInjector
abstract fun contributesSplashActivity(): SplashActivity
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
abstract fun contributesTrendingActivity(): TrendingActivity
@ContributesAndroidInjector
abstract fun contributesEditFilterActivity(): EditFilterActivity
@ContributesAndroidInjector
abstract fun contributesPrivacyPolicyActivity(): PrivacyPolicyActivity
}

View File

@ -1,48 +0,0 @@
/* Copyright 2018 charlag
*
* This file is a part of Pachli.
*
* 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.
*
* Pachli 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 app.pachli.di
import app.pachli.PachliApplication
import dagger.BindsInstance
import dagger.Component
import dagger.android.support.AndroidSupportInjectionModule
import javax.inject.Singleton
@Singleton
@Component(
modules = [
AppModule::class,
CoroutineScopeModule::class,
NetworkModule::class,
AndroidSupportInjectionModule::class,
ActivitiesModule::class,
ServicesModule::class,
BroadcastReceiverModule::class,
ViewModelModule::class,
WorkerModule::class,
],
)
interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun application(pachliApp: PachliApplication): Builder
fun build(): AppComponent
}
fun inject(app: PachliApplication)
}

View File

@ -1,79 +0,0 @@
/* Copyright 2018 charlag
*
* This file is a part of Pachli.
*
* 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.
*
* Pachli 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 app.pachli.di
import android.app.Activity
import android.app.Application
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import app.pachli.PachliApplication
import dagger.android.AndroidInjection
import dagger.android.HasAndroidInjector
import dagger.android.support.AndroidSupportInjection
object AppInjector {
fun init(app: PachliApplication) {
DaggerAppComponent.builder().application(app)
.build().inject(app)
app.registerActivityLifecycleCallbacks(
object : Application.ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
handleActivity(activity)
}
override fun onActivityPaused(activity: Activity) {
}
override fun onActivityResumed(activity: Activity) {
}
override fun onActivityStarted(activity: Activity) {
}
override fun onActivityDestroyed(activity: Activity) {
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
}
override fun onActivityStopped(activity: Activity) {
}
},
)
}
private fun handleActivity(activity: Activity) {
if (activity is HasAndroidInjector || activity is Injectable) {
AndroidInjection.inject(activity)
}
if (activity is FragmentActivity) {
activity.supportFragmentManager.registerFragmentLifecycleCallbacks(
object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentPreAttached(fm: FragmentManager, f: Fragment, context: Context) {
if (f is Injectable) {
AndroidSupportInjection.inject(f)
}
}
},
true,
)
}
}
}

View File

@ -1,35 +0,0 @@
/* Copyright 2018 Jeremiasz Nelz <remi6397(a)gmail.com>
* Copyright 2018 Conny Duck
*
* This file is a part of Pachli.
*
* 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.
*
* Pachli 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 app.pachli.di
import app.pachli.receiver.NotificationBlockStateBroadcastReceiver
import app.pachli.receiver.SendStatusBroadcastReceiver
import app.pachli.receiver.UnifiedPushBroadcastReceiver
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class BroadcastReceiverModule {
@ContributesAndroidInjector
abstract fun contributeSendStatusBroadcastReceiver(): SendStatusBroadcastReceiver
@ContributesAndroidInjector
abstract fun contributeUnifiedPushBroadcastReceiver(): UnifiedPushBroadcastReceiver
@ContributesAndroidInjector
abstract fun contributeNotificationBlockStateBroadcastReceiver(): NotificationBlockStateBroadcastReceiver
}

View File

@ -19,6 +19,8 @@ package app.pachli.di
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@ -36,8 +38,9 @@ import javax.inject.Qualifier
@Qualifier
annotation class ApplicationScope
@InstallIn(SingletonComponent::class)
@Module
class CoroutineScopeModule {
object CoroutineScopeModule {
@ApplicationScope
@Provides
fun providesApplicationScope() = CoroutineScope(SupervisorJob() + Dispatchers.Default)

View File

@ -0,0 +1,93 @@
/*
* Copyright 2023 Pachli Association
*
* This file is a part of Pachli.
*
* 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.
*
* Pachli 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 Pachli; if not,
* see <http://www.gnu.org/licenses>.
*/
package app.pachli.di
import android.content.Context
import androidx.room.Room
import androidx.room.withTransaction
import app.pachli.db.AppDatabase
import app.pachli.db.Converters
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
@Module
object DatabaseModule {
@Provides
@Singleton
fun providesDatabase(
@ApplicationContext appContext: Context,
converters: Converters,
): AppDatabase {
return Room.databaseBuilder(appContext, AppDatabase::class.java, "pachliDB")
.addTypeConverter(converters)
.allowMainThreadQueries()
.build()
}
@Provides
@Singleton
fun provideTransactionProvider(appDatabase: AppDatabase) = TransactionProvider(appDatabase)
@Provides
fun provideAccountDao(appDatabase: AppDatabase) = appDatabase.accountDao()
@Provides
fun provideInstanceDao(appDatabase: AppDatabase) = appDatabase.instanceDao()
@Provides
fun provideConversationsDao(appDatabase: AppDatabase) = appDatabase.conversationDao()
@Provides
fun provideTimelineDao(appDatabase: AppDatabase) = appDatabase.timelineDao()
@Provides
fun provideDraftDao(appDatabase: AppDatabase) = appDatabase.draftDao()
@Provides
fun provideRemoteKeyDao(appDatabase: AppDatabase) = appDatabase.remoteKeyDao()
}
/**
* Provides `operator` [invoke] function that can be used by classes that
* need to run operations across multiple DAOs in a single transaction without
* needing to inject the full [AppDatabase] in to the class.
*
* ```
* class FooRepository @Inject constructor(
* private val transactionProvider: TransactionProvider,
* private val fooDao: FooDao,
* private val barDao: BarDao,
* ) {
* suspend fun doSomething() = transactionProvider {
* fooDao.doSomethingWithFoo()
* barDao.doSomethingWithBar()
* }
* }
* ```
*/
class TransactionProvider(private val appDatabase: AppDatabase) {
/** Runs the given block in a database transaction */
suspend operator fun <R> invoke(block: suspend () -> R): R {
return appDatabase.withTransaction(block)
}
}

View File

@ -1,110 +0,0 @@
/* Copyright 2018 charlag
*
* This file is a part of Pachli.
*
* 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.
*
* Pachli 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 app.pachli.di
import app.pachli.AccountsInListFragment
import app.pachli.components.account.list.ListsForAccountFragment
import app.pachli.components.account.media.AccountMediaFragment
import app.pachli.components.accountlist.AccountListFragment
import app.pachli.components.conversation.ConversationsFragment
import app.pachli.components.instancemute.fragment.InstanceListFragment
import app.pachli.components.notifications.NotificationsFragment
import app.pachli.components.preference.AccountPreferencesFragment
import app.pachli.components.preference.NotificationPreferencesFragment
import app.pachli.components.preference.PreferencesFragment
import app.pachli.components.report.fragments.ReportDoneFragment
import app.pachli.components.report.fragments.ReportNoteFragment
import app.pachli.components.report.fragments.ReportStatusesFragment
import app.pachli.components.search.fragments.SearchAccountsFragment
import app.pachli.components.search.fragments.SearchHashtagsFragment
import app.pachli.components.search.fragments.SearchStatusesFragment
import app.pachli.components.timeline.TimelineFragment
import app.pachli.components.trending.TrendingLinksFragment
import app.pachli.components.trending.TrendingTagsFragment
import app.pachli.components.viewthread.ViewThreadFragment
import app.pachli.components.viewthread.edits.ViewEditsFragment
import app.pachli.fragment.ViewVideoFragment
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class FragmentBuildersModule {
@ContributesAndroidInjector
abstract fun accountListFragment(): AccountListFragment
@ContributesAndroidInjector
abstract fun accountMediaFragment(): AccountMediaFragment
@ContributesAndroidInjector
abstract fun viewThreadFragment(): ViewThreadFragment
@ContributesAndroidInjector
abstract fun viewEditsFragment(): ViewEditsFragment
@ContributesAndroidInjector
abstract fun timelineFragment(): TimelineFragment
@ContributesAndroidInjector
abstract fun notificationsFragment(): NotificationsFragment
@ContributesAndroidInjector
abstract fun notificationPreferencesFragment(): NotificationPreferencesFragment
@ContributesAndroidInjector
abstract fun accountPreferencesFragment(): AccountPreferencesFragment
@ContributesAndroidInjector
abstract fun conversationsFragment(): ConversationsFragment
@ContributesAndroidInjector
abstract fun accountInListsFragment(): AccountsInListFragment
@ContributesAndroidInjector
abstract fun reportStatusesFragment(): ReportStatusesFragment
@ContributesAndroidInjector
abstract fun reportNoteFragment(): ReportNoteFragment
@ContributesAndroidInjector
abstract fun reportDoneFragment(): ReportDoneFragment
@ContributesAndroidInjector
abstract fun instanceListFragment(): InstanceListFragment
@ContributesAndroidInjector
abstract fun searchStatusesFragment(): SearchStatusesFragment
@ContributesAndroidInjector
abstract fun searchAccountFragment(): SearchAccountsFragment
@ContributesAndroidInjector
abstract fun searchHashtagsFragment(): SearchHashtagsFragment
@ContributesAndroidInjector
abstract fun preferencesFragment(): PreferencesFragment
@ContributesAndroidInjector
abstract fun listsForAccountFragment(): ListsForAccountFragment
@ContributesAndroidInjector
abstract fun trendingTagsFragment(): TrendingTagsFragment
@ContributesAndroidInjector
abstract fun trendingLinksFragment(): TrendingLinksFragment
@ContributesAndroidInjector
abstract fun viewVideoFragment(): ViewVideoFragment
}

View File

@ -1,18 +0,0 @@
/* Copyright 2018 charlag
*
* This file is a part of Pachli.
*
* 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.
*
* Pachli 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 app.pachli.di
interface Injectable

View File

@ -1,4 +1,5 @@
/* Copyright 2018 Conny Duck
/*
* Copyright 2023 Pachli Association
*
* This file is a part of Pachli.
*
@ -10,17 +11,25 @@
* 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>. */
* You should have received a copy of the GNU General Public License along with Pachli; if not,
* see <http://www.gnu.org/licenses>.
*/
package app.pachli.di
import app.pachli.service.SendStatusService
import app.pachli.network.MastodonApi
import dagger.Module
import dagger.android.ContributesAndroidInjector
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import retrofit2.Retrofit
import retrofit2.create
import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
@Module
abstract class ServicesModule {
@ContributesAndroidInjector
abstract fun contributesSendStatusService(): SendStatusService
object MastodonApiModule {
@Provides
@Singleton
fun providesApi(retrofit: Retrofit): MastodonApi = retrofit.create()
}

View File

@ -35,6 +35,9 @@ import com.google.gson.Gson
import com.google.gson.GsonBuilder
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import okhttp3.Cache
import okhttp3.OkHttp
import okhttp3.OkHttpClient
@ -49,8 +52,10 @@ import java.util.Date
import java.util.concurrent.TimeUnit
import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
@Module
class NetworkModule {
object NetworkModule {
private const val TAG = "NetworkModule"
@Provides
@Singleton
@ -62,7 +67,7 @@ class NetworkModule {
@Singleton
fun providesHttpClient(
accountManager: AccountManager,
context: Context,
@ApplicationContext context: Context,
preferences: SharedPreferences,
): OkHttpClient {
val httpProxyEnabled = preferences.getBoolean(HTTP_PROXY_ENABLED, false)
@ -118,10 +123,6 @@ class NetworkModule {
.build()
}
@Provides
@Singleton
fun providesApi(retrofit: Retrofit): MastodonApi = retrofit.create()
@Provides
@Singleton
fun providesMediaUploadApi(retrofit: Retrofit, okHttpClient: OkHttpClient): MediaUploadApi {
@ -135,8 +136,4 @@ class NetworkModule {
.build()
.create()
}
companion object {
private const val TAG = "NetworkModule"
}
}

View File

@ -1,4 +1,5 @@
/* Copyright 2018 charlag
/*
* Copyright 2023 Pachli Association
*
* This file is a part of Pachli.
*
@ -10,43 +11,27 @@
* 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>. */
* You should have received a copy of the GNU General Public License along with Pachli; if not,
* see <http://www.gnu.org/licenses>.
*/
package app.pachli.di
import android.app.Application
import android.content.Context
import android.content.SharedPreferences
import androidx.preference.PreferenceManager
import androidx.room.Room
import app.pachli.PachliApplication
import app.pachli.db.AppDatabase
import app.pachli.db.Converters
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
@Module
class AppModule {
@Provides
fun providesApplication(app: PachliApplication): Application = app
@Provides
fun providesContext(app: Application): Context = app
object PreferencesModule {
@Provides
@Singleton
fun providesSharedPreferences(app: Application): SharedPreferences {
return PreferenceManager.getDefaultSharedPreferences(app)
}
@Provides
@Singleton
fun providesDatabase(appContext: Context, converters: Converters): AppDatabase {
return Room.databaseBuilder(appContext, AppDatabase::class.java, "pachliDB")
.addTypeConverter(converters)
.allowMainThreadQueries()
.build()
}
}

View File

@ -1,195 +0,0 @@
/*
* Copyright 2023 Tusky Contributors
*
* This file is a part of Pachli.
*
* 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.
*
* Pachli 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>.
*/
// from https://proandroiddev.com/viewmodel-with-dagger2-architecture-components-2e06f06c9455
package app.pachli.di
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import app.pachli.components.account.AccountViewModel
import app.pachli.components.account.list.ListsForAccountViewModel
import app.pachli.components.account.media.AccountMediaViewModel
import app.pachli.components.announcements.AnnouncementsViewModel
import app.pachli.components.compose.ComposeViewModel
import app.pachli.components.conversation.ConversationsViewModel
import app.pachli.components.drafts.DraftsViewModel
import app.pachli.components.filters.EditFilterViewModel
import app.pachli.components.filters.FiltersViewModel
import app.pachli.components.followedtags.FollowedTagsViewModel
import app.pachli.components.login.LoginWebViewViewModel
import app.pachli.components.notifications.NotificationsViewModel
import app.pachli.components.report.ReportViewModel
import app.pachli.components.scheduled.ScheduledStatusViewModel
import app.pachli.components.search.SearchViewModel
import app.pachli.components.timeline.viewmodel.CachedTimelineViewModel
import app.pachli.components.timeline.viewmodel.NetworkTimelineViewModel
import app.pachli.components.trending.viewmodel.TrendingLinksViewModel
import app.pachli.components.trending.viewmodel.TrendingTagsViewModel
import app.pachli.components.viewthread.ViewThreadViewModel
import app.pachli.components.viewthread.edits.ViewEditsViewModel
import app.pachli.viewmodel.AccountsInListViewModel
import app.pachli.viewmodel.EditProfileViewModel
import app.pachli.viewmodel.ListsViewModel
import dagger.Binds
import dagger.MapKey
import dagger.Module
import dagger.multibindings.IntoMap
import javax.inject.Inject
import javax.inject.Provider
import javax.inject.Singleton
import kotlin.reflect.KClass
@Singleton
class ViewModelFactory @Inject constructor(private val viewModels: MutableMap<Class<out ViewModel>, Provider<ViewModel>>) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T = viewModels[modelClass]?.get() as T
}
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
@Module
abstract class ViewModelModule {
@Binds
internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
@Binds
@IntoMap
@ViewModelKey(AccountViewModel::class)
internal abstract fun accountViewModel(viewModel: AccountViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(EditProfileViewModel::class)
internal abstract fun editProfileViewModel(viewModel: EditProfileViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ConversationsViewModel::class)
internal abstract fun conversationsViewModel(viewModel: ConversationsViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ListsViewModel::class)
internal abstract fun listsViewModel(viewModel: ListsViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(AccountsInListViewModel::class)
internal abstract fun accountsInListViewModel(viewModel: AccountsInListViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ReportViewModel::class)
internal abstract fun reportViewModel(viewModel: ReportViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(SearchViewModel::class)
internal abstract fun searchViewModel(viewModel: SearchViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ComposeViewModel::class)
internal abstract fun composeViewModel(viewModel: ComposeViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ScheduledStatusViewModel::class)
internal abstract fun scheduledStatusViewModel(viewModel: ScheduledStatusViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(AnnouncementsViewModel::class)
internal abstract fun announcementsViewModel(viewModel: AnnouncementsViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(DraftsViewModel::class)
internal abstract fun draftsViewModel(viewModel: DraftsViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(CachedTimelineViewModel::class)
internal abstract fun cachedTimelineViewModel(viewModel: CachedTimelineViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(NetworkTimelineViewModel::class)
internal abstract fun networkTimelineViewModel(viewModel: NetworkTimelineViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ViewThreadViewModel::class)
internal abstract fun viewThreadViewModel(viewModel: ViewThreadViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ViewEditsViewModel::class)
internal abstract fun viewEditsViewModel(viewModel: ViewEditsViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(AccountMediaViewModel::class)
internal abstract fun accountMediaViewModel(viewModel: AccountMediaViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(LoginWebViewViewModel::class)
internal abstract fun loginWebViewViewModel(viewModel: LoginWebViewViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(FollowedTagsViewModel::class)
internal abstract fun followedTagsViewModel(viewModel: FollowedTagsViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ListsForAccountViewModel::class)
internal abstract fun listsForAccountViewModel(viewModel: ListsForAccountViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(NotificationsViewModel::class)
internal abstract fun notificationsViewModel(viewModel: NotificationsViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(TrendingTagsViewModel::class)
internal abstract fun trendingTagsViewModel(viewModel: TrendingTagsViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(TrendingLinksViewModel::class)
internal abstract fun trendingLinksViewModel(viewModel: TrendingLinksViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(FiltersViewModel::class)
internal abstract fun filtersViewModel(viewModel: FiltersViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(EditFilterViewModel::class)
internal abstract fun editFilterViewModel(viewModel: EditFilterViewModel): ViewModel
// Add more ViewModels here
}

View File

@ -24,6 +24,8 @@ import app.pachli.worker.PruneCacheWorker
import dagger.Binds
import dagger.MapKey
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.IntoMap
import kotlin.reflect.KClass
@ -31,6 +33,7 @@ import kotlin.reflect.KClass
@MapKey
annotation class WorkerKey(val value: KClass<out ListenableWorker>)
@InstallIn(SingletonComponent::class)
@Module
abstract class WorkerModule {
@Binds

View File

@ -46,7 +46,6 @@ import app.pachli.components.compose.ComposeActivity.ComposeOptions
import app.pachli.components.report.ReportActivity.Companion.getIntent
import app.pachli.db.AccountEntity
import app.pachli.db.AccountManager
import app.pachli.di.Injectable
import app.pachli.entity.Attachment
import app.pachli.entity.Status
import app.pachli.interfaces.AccountSelectionListener
@ -68,7 +67,7 @@ import javax.inject.Inject
* adapters. I feel like the profile pages and thread viewer, which I haven't made yet, will also
* overlap functionality. So, I'm momentarily leaving it and hopefully working on those will clear
* up what needs to be where. */
abstract class SFragment : Fragment(), Injectable {
abstract class SFragment : Fragment() {
protected abstract fun removeItem(position: Int)
protected abstract fun onReblog(reblog: Boolean, position: Int)
private lateinit var bottomSheetActivity: BottomSheetActivity

View File

@ -50,7 +50,6 @@ import app.pachli.BuildConfig
import app.pachli.R
import app.pachli.ViewMediaActivity
import app.pachli.databinding.FragmentViewVideoBinding
import app.pachli.di.Injectable
import app.pachli.entity.Attachment
import app.pachli.util.hide
import app.pachli.util.viewBinding
@ -59,12 +58,14 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import okhttp3.OkHttpClient
import javax.inject.Inject
import kotlin.math.abs
@UnstableApi
class ViewVideoFragment : ViewMediaFragment(), Injectable {
@AndroidEntryPoint
class ViewVideoFragment : ViewMediaFragment() {
interface VideoActionsListener {
fun onDismiss()
}

Some files were not shown because too many files have changed in this diff Show More