Skip to content

Commit 2877fbc

Browse files
committed
fix: resolve issues with annotations with special characters, show app bottom sheet on annotation focus
1 parent a7718ab commit 2877fbc

File tree

12 files changed

+141
-42
lines changed

12 files changed

+141
-42
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package io.literal.model;
2+
3+
public enum SourceInitializationStatus {
4+
UNINITIALIZED,
5+
IN_PROGRESS,
6+
FAILED,
7+
INITIALIZED
8+
}

packages/android/app/src/main/java/io/literal/model/WebArchive.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import android.os.Bundle;
55
import android.os.Parcel;
66
import android.os.Parcelable;
7+
import android.util.Log;
78
import android.webkit.WebResourceRequest;
89

910
import org.apache.commons.io.IOUtils;
@@ -291,7 +292,6 @@ private BodyPart addScriptsToBodyPart(BodyPart bodyPart, List<HTMLScriptElement>
291292
}
292293

293294
public Optional<BodyPart> resolveWebResourceRequest(WebResourceRequest request, boolean isJavaScriptEnabled) {
294-
295295
Optional<BodyPart> optionalBodyPart = Optional.empty();
296296

297297
// If JavaScript is disabled, attempt to find the original index document using a custom header added

packages/android/app/src/main/java/io/literal/repository/ScriptRepository.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.literal.repository;
22

33
import android.content.res.AssetManager;
4+
import android.util.Log;
45

56
import org.apache.commons.io.IOUtils;
67
import org.json.JSONArray;
@@ -10,6 +11,7 @@
1011
import java.io.IOException;
1112
import java.nio.charset.StandardCharsets;
1213
import java.util.Optional;
14+
import java.util.regex.Matcher;
1315

1416
import io.literal.lib.JsonArrayUtil;
1517
import io.literal.model.Annotation;
@@ -70,7 +72,7 @@ public static String getAnnotationRendererScript(AssetManager assetManager, Anno
7072
return scriptOutput
7173
.replaceAll(
7274
"process\\.env\\.PARAM_ANNOTATIONS",
73-
paramAnnotations.substring(1, paramAnnotations.length() - 1)
75+
Matcher.quoteReplacement(paramAnnotations)
7476
)
7577
.replaceAll(
7678
"process\\.env\\.PARAM_FOCUSED_ANNOTATION_ID",
@@ -80,8 +82,6 @@ public static String getAnnotationRendererScript(AssetManager assetManager, Anno
8082
ErrorRepository.captureException(e);
8183
return null;
8284
}
83-
84-
8585
}
8686

8787
public static String getGetAnnotationBoundingBoxScript(AssetManager assetManager, JSONObject paramAnnotation) {
@@ -100,7 +100,7 @@ public static String getGetAnnotationBoundingBoxScript(AssetManager assetManager
100100
return scriptOutput
101101
.replaceAll(
102102
"process\\.env\\.PARAM_ANNOTATION",
103-
stringifiedParamAnnotation.substring(1, stringifiedParamAnnotation.length() - 1)
103+
Matcher.quoteReplacement(stringifiedParamAnnotation)
104104
);
105105
}
106106
}

packages/android/app/src/main/java/io/literal/repository/WebArchiveRepository.java

-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ public static Optional<BodyPart> createBodyPart(WebResourceRequest webResourceRe
8282
RawField rawField = new RawField(FieldName.CONTENT_LOCATION, webResourceRequest.getUrl().toString());
8383
ContentLocationField contentLocationField = ContentLocationFieldImpl.PARSER.parse(rawField, DecodeMonitor.SILENT);
8484

85-
Log.i("createBodyPart", webResourceRequest.getUrl().toString());
8685

8786
return Optional.of(
8887
BodyPartBuilder.create()

packages/android/app/src/main/java/io/literal/ui/activity/MainActivity.java

+41-12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import androidx.activity.result.contract.ActivityResultContracts;
1616
import androidx.annotation.NonNull;
1717
import androidx.fragment.app.FragmentManager;
18+
import androidx.fragment.app.FragmentTransaction;
1819
import androidx.lifecycle.Lifecycle;
1920
import androidx.lifecycle.Observer;
2021
import androidx.lifecycle.ViewModelProvider;
@@ -40,6 +41,7 @@
4041
import io.literal.lib.WebEvent;
4142
import io.literal.lib.WebRoutes;
4243
import io.literal.model.Annotation;
44+
import io.literal.model.SourceInitializationStatus;
4345
import io.literal.model.SourceWebViewAnnotation;
4446
import io.literal.model.User;
4547
import io.literal.repository.AnalyticsRepository;
@@ -63,6 +65,7 @@ public class MainActivity extends InstrumentedActivity {
6365
private SourceWebViewViewModel sourceWebViewViewModelBottomSheet;
6466
private AuthenticationViewModel authenticationViewModel;
6567
private AppWebView appWebViewPrimaryFragment = null;
68+
6669
private final BroadcastReceiver annotationCreatedBroadcastReceiver = new BroadcastReceiver() {
6770
@Override
6871
public void onReceive(Context context, Intent intent) {
@@ -84,6 +87,7 @@ public void onReceive(Context context, Intent intent) {
8487
};
8588
private SourceWebView sourceWebViewBottomSheetFragment = null;
8689
private AppWebView appWebViewBottomSheetFragment = null;
90+
private Observer<SourceInitializationStatus> sourceInitializationStatusObserver;
8791
private final ActivityResultLauncher<Intent> createAnnotationFromSourceLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), MainActivity.this::handleCreateAnnotationFromSourceResult);
8892

8993
@Override
@@ -185,23 +189,38 @@ private CompletableFuture<User> initializeViewModel() {
185189
.ifPresent((s) -> {
186190
if (displayBottomSheet) {
187191
sourceWebViewViewModelBottomSheet.getBottomSheetBehavior().ifPresent(b -> b.setState(BottomSheetBehavior.STATE_EXPANDED));
192+
193+
SourceInitializationStatus sourceInitializationStatus = sourceWebViewViewModelBottomSheet.getSourceInitializationStatus().getValue();
188194
// Source wil already be initialized if it was previously accessed or it may have loaded in a previous call where `displayBottomSheet` was false.
189-
if (sourceWebViewViewModelBottomSheet.getSourceHasFinishedInitializing().getValue()) {
195+
if (sourceInitializationStatus.equals(SourceInitializationStatus.INITIALIZED)) {
190196
appWebViewViewModelBottomSheet.setBottomSheetState(BottomSheetBehavior.STATE_COLLAPSED);
191197
boolean javascriptEnabled = Optional.ofNullable(sourceWebViewViewModelBottomSheet).map((vm) -> vm.getSourceJavaScriptConfig().getValue().isEnabled()).orElse(true);
192198
if (!javascriptEnabled) {
193199
ToastRepository.show(this, R.string.toast_javascript_disabled, ToastRepository.STYLE_DARK_ACCENT);
194200
}
201+
} else if (sourceInitializationStatus.equals(SourceInitializationStatus.FAILED)) {
202+
ToastRepository.show(this, R.string.toast_annotation_renderer_failed_to_initialize, ToastRepository.STYLE_DARK_ACCENT);
195203
} else {
196-
sourceWebViewViewModelBottomSheet.getSourceHasFinishedInitializing().observe(this, new Observer<Boolean>() {
204+
if (sourceInitializationStatusObserver != null) {
205+
sourceWebViewViewModelBottomSheet.getSourceInitializationStatus().removeObserver(sourceInitializationStatusObserver);
206+
}
207+
sourceInitializationStatusObserver = new Observer<SourceInitializationStatus>() {
197208
@Override
198-
public void onChanged(Boolean sourceHasFinishedInitializing) {
199-
if (sourceHasFinishedInitializing) {
200-
sourceWebViewViewModelBottomSheet.getSourceHasFinishedInitializing().removeObserver(this);
209+
public void onChanged(SourceInitializationStatus sourceInitializationStatus) {
210+
int sourceWebViewBottomSheetState = sourceWebViewViewModelBottomSheet.getBottomSheetBehavior()
211+
.map(BottomSheetBehavior::getState)
212+
.orElse(BottomSheetBehavior.STATE_HIDDEN);
213+
214+
if (sourceInitializationStatus.equals(SourceInitializationStatus.INITIALIZED) && sourceWebViewBottomSheetState != BottomSheetBehavior.STATE_HIDDEN) {
201215
appWebViewViewModelBottomSheet.setBottomSheetState(BottomSheetBehavior.STATE_COLLAPSED);
202216
}
217+
218+
if (sourceInitializationStatus.equals(SourceInitializationStatus.INITIALIZED) || sourceInitializationStatus.equals(SourceInitializationStatus.FAILED)) {
219+
sourceWebViewViewModelBottomSheet.getSourceInitializationStatus().removeObserver(this);
220+
}
203221
}
204-
});
222+
};
223+
sourceWebViewViewModelBottomSheet.getSourceInitializationStatus().observe(this, sourceInitializationStatusObserver);
205224
}
206225
}
207226
});
@@ -286,13 +305,23 @@ private void commitFragments(Bundle savedInstanceState, String initialUrl, User
286305
this.handleCreateAnnotationFromSource(sourceUrl.toString());
287306
});
288307

289-
getSupportFragmentManager()
308+
FragmentTransaction fragmentTransaction = getSupportFragmentManager()
290309
.beginTransaction()
291-
.setReorderingAllowed(true)
292-
.add(R.id.fragment_container, appWebViewPrimaryFragment)
293-
.add(R.id.source_web_view_bottom_sheet_fragment_container, sourceWebViewBottomSheetFragment)
294-
.add(R.id.app_web_view_bottom_sheet_fragment_container, appWebViewBottomSheetFragment)
295-
.commit();
310+
.setReorderingAllowed(true);
311+
312+
if (!appWebViewPrimaryFragment.isAdded()) {
313+
fragmentTransaction.add(R.id.fragment_container, appWebViewPrimaryFragment);
314+
}
315+
if (!sourceWebViewBottomSheetFragment.isAdded()) {
316+
fragmentTransaction.add(R.id.source_web_view_bottom_sheet_fragment_container, sourceWebViewBottomSheetFragment);
317+
}
318+
if (!appWebViewBottomSheetFragment.isAdded()) {
319+
fragmentTransaction.add(R.id.app_web_view_bottom_sheet_fragment_container, appWebViewBottomSheetFragment);
320+
}
321+
322+
if (!fragmentTransaction.isEmpty()) {
323+
fragmentTransaction.commit();
324+
}
296325
}
297326

298327
private void handleCreateAnnotationFromSource(String sourceUrl) {

packages/android/app/src/main/java/io/literal/ui/activity/ShareTargetHandler.java

+11-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import androidx.annotation.NonNull;
1111
import androidx.fragment.app.Fragment;
1212
import androidx.fragment.app.FragmentContainerView;
13+
import androidx.lifecycle.Observer;
1314
import androidx.lifecycle.ViewModelProvider;
1415

1516
import com.amazonaws.amplify.generated.graphql.GetAnnotationQuery;
@@ -33,6 +34,7 @@
3334
import io.literal.lib.WebRoutes;
3435
import io.literal.model.Annotation;
3536
import io.literal.model.ErrorRepositoryLevel;
37+
import io.literal.model.SourceInitializationStatus;
3638
import io.literal.model.SourceWebViewAnnotation;
3739
import io.literal.model.StorageObject;
3840
import io.literal.model.User;
@@ -124,11 +126,15 @@ private void handleIntent(Intent intent, User user) {
124126
private void installSourceWebView(String sourceWebViewUri, String appWebViewUri) {
125127
sourceWebViewViewModel = new ViewModelProvider(this).get(SourceWebViewViewModel.class);
126128

127-
sourceWebViewViewModel.getSourceHasFinishedInitializing().observe(this, hasFinishedInitializing -> {
128-
ViewGroup splash = findViewById(R.id.share_target_handler_splash);
129-
if (hasFinishedInitializing && splash.getVisibility() == View.VISIBLE) {
130-
splash.setVisibility(View.INVISIBLE);
131-
ToastRepository.show(this, R.string.toast_create_from_source);
129+
sourceWebViewViewModel.getSourceInitializationStatus().observe(this, new Observer<SourceInitializationStatus>() {
130+
@Override
131+
public void onChanged(SourceInitializationStatus sourceInitializationStatus) {
132+
ViewGroup splash = ShareTargetHandler.this.findViewById(R.id.share_target_handler_splash);
133+
if (sourceInitializationStatus.equals(SourceInitializationStatus.INITIALIZED) && splash.getVisibility() == View.VISIBLE) {
134+
splash.setVisibility(View.INVISIBLE);
135+
ToastRepository.show(ShareTargetHandler.this, R.string.toast_create_from_source);
136+
sourceWebViewViewModel.getSourceInitializationStatus().removeObserver(this);
137+
}
132138
}
133139
});
134140

0 commit comments

Comments
 (0)