Skip to content

Commit cf9cd01

Browse files
authored
Merge branch 'zotero:master' into master
2 parents 3a41f6a + da71a48 commit cf9cd01

File tree

81 files changed

+1045
-602
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1045
-602
lines changed

Diff for: app/build.gradle.kts

+5
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ android {
8080
buildConfigField("boolean", "EVENT_AND_CRASH_LOGGING_ENABLED", "false")
8181
manifestPlaceholders["enableCrashReporting"] = false
8282
extra.set("enableCrashlytics", false)
83+
//Prevent variables from being 'optimized out' during debug,
84+
//so it becomes possible to see their values in debugger
85+
kotlinOptions {
86+
freeCompilerArgs = freeCompilerArgs + listOf("-Xdebug")
87+
}
8388
}
8489
getByName("release") {
8590
isDebuggable = false

Diff for: app/src/main/java/org/zotero/android/androidx/text/StyledTextHelper.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ object StyledTextHelper {
192192

193193
private fun getTypeface(context: Context, font: String): Typeface {
194194
val resource = when (font) {
195-
"bold" -> Fonts.suisse_intl_bold
195+
"bold" -> return Typeface.DEFAULT_BOLD
196196
"reckless" -> Fonts.reckless_neue_book
197197
"grenette_semibold_italic" -> Fonts.grenette_semibold_italic_pro
198198
else -> error("Unknown font: $font!")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.zotero.android.api
2+
3+
import retrofit2.http.GET
4+
import retrofit2.http.Url
5+
6+
interface NonZoteroNoRedirectApi {
7+
@GET
8+
suspend fun sendGet(@Url url: String): retrofit2.Response<Void>
9+
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.zotero.android.api.annotations;
2+
3+
import static java.lang.annotation.RetentionPolicy.CLASS;
4+
5+
import java.lang.annotation.Retention;
6+
7+
import javax.inject.Qualifier;
8+
9+
@Qualifier
10+
@Retention(CLASS)
11+
public @interface ForNonZoteroNoRedirectsApi {
12+
}

Diff for: app/src/main/java/org/zotero/android/api/annotations/ForNoRedirectsApi.java renamed to app/src/main/java/org/zotero/android/api/annotations/ForZoteroNoRedirectsApi.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88

99
@Qualifier
1010
@Retention(CLASS)
11-
public @interface ForNoRedirectsApi {
11+
public @interface ForZoteroNoRedirectsApi {
1212
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package org.zotero.android.api.module
2+
3+
import com.google.gson.Gson
4+
import dagger.Module
5+
import dagger.Provides
6+
import dagger.hilt.migration.DisableInstallInCheck
7+
import okhttp3.OkHttpClient
8+
import okhttp3.logging.HttpLoggingInterceptor.Level
9+
import org.zotero.android.api.NonZoteroNoRedirectApi
10+
import org.zotero.android.api.annotations.ForNonZoteroNoRedirectsApi
11+
import org.zotero.android.api.interceptors.HttpLoggingInterceptor
12+
import retrofit2.Retrofit
13+
import retrofit2.converter.gson.GsonConverterFactory
14+
import retrofit2.converter.scalars.ScalarsConverterFactory
15+
import javax.inject.Singleton
16+
17+
@Module
18+
@DisableInstallInCheck
19+
object NonZoteroNoRedirectModule {
20+
21+
@Provides
22+
@ForNonZoteroNoRedirectsApi
23+
fun provideRetrofitBuilder(gson: Gson): Retrofit.Builder {
24+
val stringConverter = ScalarsConverterFactory.create()
25+
val gsonConverter = GsonConverterFactory.create(gson)
26+
return Retrofit.Builder()
27+
.addConverterFactory(stringConverter)
28+
.addConverterFactory(gsonConverter)
29+
}
30+
31+
@Provides
32+
@Singleton
33+
@ForNonZoteroNoRedirectsApi
34+
fun provideRetrofit(
35+
@ForNonZoteroNoRedirectsApi builder: Retrofit.Builder,
36+
@ForNonZoteroNoRedirectsApi okHttpClient: OkHttpClient
37+
): Retrofit {
38+
return builder
39+
.baseUrl("https://dummyurl.com") //no-op as all URLs for non-zotero API are absolute
40+
.client(okHttpClient)
41+
.build()
42+
}
43+
44+
@Provides
45+
@Singleton
46+
@ForNonZoteroNoRedirectsApi
47+
fun provideOkHttpClient(
48+
): OkHttpClient {
49+
return OkHttpClient.Builder()
50+
.followRedirects(false)
51+
.addInterceptor(HttpLoggingInterceptor.createInterceptor(Level.BASIC))
52+
.build()
53+
}
54+
55+
@Provides
56+
@Singleton
57+
fun provideNonZoteroNoRedirectApi(@ForNonZoteroNoRedirectsApi retrofit: Retrofit): NonZoteroNoRedirectApi =
58+
retrofit.create(NonZoteroNoRedirectApi::class.java)
59+
60+
}

Diff for: app/src/main/java/org/zotero/android/api/module/ZoteroNoRedirectModule.kt

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import dagger.hilt.migration.DisableInstallInCheck
66
import okhttp3.OkHttpClient
77
import org.zotero.android.BuildConfig
88
import org.zotero.android.api.ZoteroNoRedirectApi
9-
import org.zotero.android.api.annotations.ForNoRedirectsApi
109
import org.zotero.android.api.annotations.ForZoteroApi
10+
import org.zotero.android.api.annotations.ForZoteroNoRedirectsApi
1111
import retrofit2.Retrofit
1212
import javax.inject.Singleton
1313

@@ -17,10 +17,10 @@ object ZoteroNoRedirectModule {
1717

1818
@Provides
1919
@Singleton
20-
@ForNoRedirectsApi
20+
@ForZoteroNoRedirectsApi
2121
fun provideRetrofit(
2222
@ForZoteroApi baseBuilder: Retrofit.Builder,
23-
@ForNoRedirectsApi okHttpClient: OkHttpClient
23+
@ForZoteroNoRedirectsApi okHttpClient: OkHttpClient
2424
): Retrofit {
2525
return baseBuilder
2626
.baseUrl(BuildConfig.BASE_API_URL)
@@ -30,7 +30,7 @@ object ZoteroNoRedirectModule {
3030

3131
@Provides
3232
@Singleton
33-
@ForNoRedirectsApi
33+
@ForZoteroNoRedirectsApi
3434
fun provideOkHttpClient(
3535
@ForZoteroApi baseClient: OkHttpClient,
3636
): OkHttpClient {
@@ -42,7 +42,7 @@ object ZoteroNoRedirectModule {
4242

4343
@Provides
4444
@Singleton
45-
fun provideZoteroNoRedirectApi(@ForNoRedirectsApi retrofit: Retrofit): ZoteroNoRedirectApi =
45+
fun provideZoteroNoRedirectApi(@ForZoteroNoRedirectsApi retrofit: Retrofit): ZoteroNoRedirectApi =
4646
retrofit.create(ZoteroNoRedirectApi::class.java)
4747

4848
}

Diff for: app/src/main/java/org/zotero/android/architecture/di/AppModule.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ import dagger.hilt.InstallIn
88
import dagger.hilt.components.SingletonComponent
99
import kotlinx.coroutines.CoroutineDispatcher
1010
import kotlinx.coroutines.SupervisorJob
11-
import org.zotero.android.api.module.ZoteroNoRedirectModule
1211
import org.zotero.android.api.module.NonZoteroApiModule
12+
import org.zotero.android.api.module.NonZoteroNoRedirectModule
1313
import org.zotero.android.api.module.WebSocketApiModule
1414
import org.zotero.android.api.module.ZoteroApiModule
15+
import org.zotero.android.api.module.ZoteroNoRedirectModule
1516
import org.zotero.android.architecture.coroutines.ApplicationScope
1617
import org.zotero.android.architecture.coroutines.Dispatchers
1718
import org.zotero.android.architecture.coroutines.QDispatchers
@@ -24,6 +25,7 @@ import javax.inject.Singleton
2425
ZoteroApiModule::class,
2526
ZoteroNoRedirectModule::class,
2627
NonZoteroApiModule::class,
28+
NonZoteroNoRedirectModule::class,
2729
WebSocketApiModule::class,
2830
]
2931
)

Diff for: app/src/main/java/org/zotero/android/architecture/navigation/CommonScreenNavigation.kt

+15-5
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ import org.zotero.android.screens.mediaviewer.video.VideoPlayerView
1818
import org.zotero.android.screens.webview.ZoteroWebViewScreen
1919
import java.io.File
2020

21+
internal const val ARG_COLLECTIONS_SCREEN = "collectionArgs"
2122
internal const val ARG_ITEM_DETAILS_SCREEN = "itemDetailsArgs"
2223
internal const val ARG_RETRIEVE_METADATA = "retrieveMetadataArgs"
2324
internal const val ARG_TAGS_FILTER = "tagsScreen"
2425
internal const val ARG_ADD_OR_EDIT_NOTE = "notesScreen"
2526

2627
fun NavGraphBuilder.allItemsScreen(
27-
navigateToCollectionsScreen: () -> Unit,
28+
navigateToCollectionsScreen: (String) -> Unit,
2829
navigateToItemDetails: (String) -> Unit,
2930
navigateToAddOrEditNote: (String) -> Unit,
3031
navigateToSinglePicker: () -> Unit,
@@ -141,7 +142,7 @@ fun NavGraphBuilder.zoterWebViewScreen(onClose: () -> Unit) {
141142
}
142143

143144
fun NavGraphBuilder.librariesScreen(
144-
navigateToCollectionsScreen: () -> Unit,
145+
navigateToCollectionsScreen: (String) -> Unit,
145146
onSettingsTapped: () -> Unit,
146147
) {
147148
composable(route = CommonScreenDestinations.LIBRARIES_SCREEN) {
@@ -183,12 +184,21 @@ fun NavGraphBuilder.loadingScreen(
183184
}
184185

185186
fun NavGraphBuilder.collectionsScreen(
187+
collectionDefaultValue: String,
186188
onBack: () -> Unit,
187-
navigateToAllItems: () -> Unit,
189+
navigateToAllItems: (String) -> Unit,
188190
navigateToCollectionEdit: () -> Unit,
189-
navigateToLibraries: () -> Unit,
191+
navigateToLibraries: (String) -> Unit,
190192
) {
191-
composable(route = CommonScreenDestinations.COLLECTIONS_SCREEN) {
193+
composable(
194+
route = "${CommonScreenDestinations.COLLECTIONS_SCREEN}/{$ARG_COLLECTIONS_SCREEN}",
195+
arguments = listOf(
196+
navArgument(ARG_COLLECTIONS_SCREEN) {
197+
type = NavType.StringType; defaultValue = collectionDefaultValue
198+
},
199+
),
200+
201+
) {
192202
CollectionsScreen(
193203
onBack = onBack,
194204
navigateToAllItems = navigateToAllItems,

Diff for: app/src/main/java/org/zotero/android/architecture/navigation/NavigationParamsMarshaller.kt

+21-9
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,50 @@ package org.zotero.android.architecture.navigation
33
import com.google.gson.Gson
44
import org.apache.commons.codec.binary.Base64
55
import org.apache.commons.io.IOUtils
6+
import java.nio.charset.Charset
67
import java.nio.charset.StandardCharsets
78
import javax.inject.Inject
89
import javax.inject.Singleton
910

1011
@Singleton
1112
class NavigationParamsMarshaller @Inject constructor(val gson: Gson) {
1213

13-
fun encodeObjectToBase64(data: Any): String {
14+
fun encodeObjectToBase64(data: Any, charset: Charset = StandardCharsets.US_ASCII): String {
1415
val json = gson.toJson(data)
15-
val encodedJson = encodeJsonToBase64(json)
16-
return encodedJson
16+
val encodedJson = encodeJsonToBase64(stringToEncode = json, charset = charset)
17+
val escaped = encodedJson.replace('/', '+').replace('_', '-')
18+
return escaped
1719
}
1820

19-
private fun encodeJsonToBase64(stringToEncode: String): String {
21+
private fun encodeJsonToBase64(
22+
stringToEncode: String,
23+
charset: Charset
24+
): String {
2025
val bytes = IOUtils.toByteArray(stringToEncode);
2126
val encoded: ByteArray = Base64.encodeBase64(bytes)
22-
return String(encoded, StandardCharsets.US_ASCII)
27+
return String(encoded, charset)
2328
}
2429

25-
inline fun <reified T> decodeObjectFromBase64(encodedJson: String): T {
26-
val decodedJson = decodeJsonFromBase64Binary(encodedJson)
30+
inline fun <reified T> decodeObjectFromBase64(
31+
encodedJson: String,
32+
charset: Charset = StandardCharsets.US_ASCII
33+
): T {
34+
val unescaped = encodedJson.replace('-', '_').replace('+', '/')
35+
val decodedJson = decodeJsonFromBase64Binary(encodedJson = unescaped, charset = charset)
2736
return unmarshal(decodedJson)
2837
}
2938

3039
inline fun <reified T> unmarshal(data: String): T {
3140
return gson.fromJson(data, T::class.java)
3241
}
3342

34-
fun decodeJsonFromBase64Binary(encodedJson: String): String {
43+
fun decodeJsonFromBase64Binary(
44+
encodedJson: String,
45+
charset: Charset
46+
): String {
3547
val bytes = IOUtils.toByteArray(encodedJson);
3648
val decodedJson: ByteArray = Base64.decodeBase64(bytes)
37-
return String(decodedJson, StandardCharsets.US_ASCII)
49+
return String(decodedJson, charset)
3850
}
3951

4052
}

Diff for: app/src/main/java/org/zotero/android/architecture/navigation/phone/DashboardRootPhoneNavigation.kt

+14-10
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ internal const val ARG_ADD_BY_IDENTIFIER = "addByIdentifierArg"
6161

6262
@Composable
6363
internal fun DashboardRootPhoneNavigation(
64+
collectionDefaultValue: String,
6465
onPickFile: (callPoint: EventBusConstants.FileWasSelected.CallPoint) -> Unit,
6566
onOpenFile: (file: File, mimeType: String) -> Unit,
6667
onOpenWebpage: (uri: Uri) -> Unit,
@@ -76,10 +77,11 @@ internal fun DashboardRootPhoneNavigation(
7677

7778

7879
LaunchedEffect(key1 = viewEffect) {
79-
when (viewEffect?.consume()) {
80+
val consumedEffect = viewEffect?.consume()
81+
when (consumedEffect) {
8082
null -> Unit
81-
DashboardViewEffect.NavigateToCollectionsScreen -> navigateToCollectionsScreen(
82-
navController
83+
is DashboardViewEffect.NavigateToCollectionsScreen -> navigateToCollectionsScreen(
84+
navController, consumedEffect.screenArgs
8385
)
8486
}
8587
}
@@ -93,10 +95,11 @@ internal fun DashboardRootPhoneNavigation(
9395
modifier = Modifier.navigationBarsPadding(), // do not draw behind nav bar
9496
) {
9597
collectionsScreen(
98+
collectionDefaultValue = collectionDefaultValue,
9699
onBack = navigation::onBack,
97100
navigateToAllItems = {
98101
toAllItems(
99-
navController = navController,
102+
navController = navController,it
100103
)
101104
},
102105
navigateToLibraries = {
@@ -106,7 +109,7 @@ internal fun DashboardRootPhoneNavigation(
106109
)
107110
librariesScreen(
108111
navigateToCollectionsScreen = {
109-
navigateToCollectionsScreen(navController)
112+
navigateToCollectionsScreen(navController, it)
110113
},
111114
onSettingsTapped = { navigation.toSettingsScreen() }
112115
)
@@ -240,10 +243,10 @@ internal fun DashboardRootPhoneNavigation(
240243
}
241244
}
242245

243-
private fun navigateToCollectionsScreen(navController: NavHostController) {
246+
private fun navigateToCollectionsScreen(navController: NavHostController, collectionArgs: String) {
244247
navController.popBackStack(navController.graph.id, inclusive = true)
245248
navController.navigate(CommonScreenDestinations.LIBRARIES_SCREEN)
246-
navController.navigate(CommonScreenDestinations.COLLECTIONS_SCREEN)
249+
navController.navigate("${CommonScreenDestinations.COLLECTIONS_SCREEN}/$collectionArgs")
247250
}
248251

249252
private object DashboardRootPhoneDestinations {
@@ -257,8 +260,8 @@ private object DashboardRootPhoneDestinations {
257260

258261
}
259262

260-
private fun ZoteroNavigation.toCollectionsScreen() {
261-
navController.navigate(CommonScreenDestinations.COLLECTIONS_SCREEN) {
263+
private fun ZoteroNavigation.toCollectionsScreen(params: String) {
264+
navController.navigate("${CommonScreenDestinations.COLLECTIONS_SCREEN}/$params") {
262265
launchSingleTop = true
263266
}
264267
}
@@ -289,9 +292,10 @@ private fun ZoteroNavigation.toRetrieveMetadata(args: String) {
289292

290293
private fun toAllItems(
291294
navController: NavHostController,
295+
collectionArgs: String,
292296
) {
293297
navController.popBackStack(navController.graph.id, inclusive = true)
294-
navController.navigate(CommonScreenDestinations.COLLECTIONS_SCREEN)
298+
navController.navigate("${CommonScreenDestinations.COLLECTIONS_SCREEN}/$collectionArgs")
295299
navController.navigate(CommonScreenDestinations.ALL_ITEMS)
296300
}
297301

Diff for: app/src/main/java/org/zotero/android/architecture/navigation/tablet/DashboardRootTabletNavigationScreen.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import java.io.File
2525

2626
@Composable
2727
internal fun DashboardRootTabletNavigationScreen(
28+
collectionDefaultValue: String,
2829
onPickFile: (callPoint: EventBusConstants.FileWasSelected.CallPoint) -> Unit,
2930
onOpenFile: (file: File, mimeType: String) -> Unit,
3031
onOpenWebpage: (uri: Uri) -> Unit,
@@ -40,7 +41,7 @@ internal fun DashboardRootTabletNavigationScreen(
4041
val rightPaneNavigation = remember(rightPaneNavController) {
4142
ZoteroNavigation(rightPaneNavController, dispatcher)
4243
}
43-
val navigateAndPopAllItemsScreen: () -> Unit = {
44+
val navigateAndPopAllItemsScreen: (String) -> Unit = {
4445
rightPaneNavController.navigate(CommonScreenDestinations.ALL_ITEMS) {
4546
popUpTo(0)
4647
}
@@ -50,6 +51,7 @@ internal fun DashboardRootTabletNavigationScreen(
5051
Row(modifier = Modifier.fillMaxSize()) {
5152
Box(modifier = Modifier.weight(0.35f)) {
5253
TabletLeftPaneNavigation(
54+
collectionDefaultValue = collectionDefaultValue,
5355
viewEffect = viewEffect,
5456
navigateAndPopAllItemsScreen = navigateAndPopAllItemsScreen,
5557
onOpenWebpage = onOpenWebpage

0 commit comments

Comments
 (0)