Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@
android:exported="true"
android:label="添加附言" />
<activity android:name=".general.PageHost" />
<activity
android:name=".module.vshare.VshareWebActivity"
android:exported="false"
android:theme="@style/NoneSlideBackableTheme"
android:configChanges="orientation|keyboardHidden|screenSize" />
</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ protected void init() {
Navigator.from(getContext()).to(CreateTopicActivity.class).start();
break;
case R.id.vshare_nav_item:
Utils.openInBrowser("https://v2er.app/vshare", getContext());
me.ghui.v2er.module.vshare.VshareWebActivity.open(getContext());
mVshareVersionChecker.markAsViewed();
updateVshareBadge();
break;
Expand Down
173 changes: 173 additions & 0 deletions app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package me.ghui.v2er.module.vshare;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;

import androidx.appcompat.app.AppCompatActivity;

import butterknife.BindView;
import butterknife.ButterKnife;
import me.ghui.v2er.R;
import me.ghui.v2er.util.DarkModelUtils;

/**
* Fullscreen WebView Activity for displaying vshare page
* with automatic theme adaptation
*/
public class VshareWebActivity extends AppCompatActivity {

private static final String VSHARE_BASE_URL = "https://v2er.app/vshare";

@BindView(R.id.webview)
WebView mWebView;

@BindView(R.id.progress_bar)
ProgressBar mProgressBar;

public static void open(Context context) {
Intent intent = new Intent(context, VshareWebActivity.class);
context.startActivity(intent);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Hide action bar if present
if (getSupportActionBar() != null) {
getSupportActionBar().hide();
}

// Set SystemUI flags to match MainActivity's edge-to-edge behavior
View decorView = getWindow().getDecorView();
int systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;

// Set status bar icon color based on theme
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (!DarkModelUtils.isDarkMode()) {
// Light mode: use dark status bar icons
systemUiVisibility |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
}
}

decorView.setSystemUiVisibility(systemUiVisibility);

setContentView(R.layout.activity_vshare_web);
ButterKnife.bind(this);

setupWebView();

// Compute URL with theme parameter based on current app theme
String url = VSHARE_BASE_URL;
if (DarkModelUtils.isDarkMode()) {
url += "?theme=dark";
} else {
url += "?theme=light";
}
mWebView.loadUrl(url);
}

@SuppressLint("SetJavaScriptEnabled")
private void setupWebView() {
WebSettings settings = mWebView.getSettings();

// Enable JavaScript
settings.setJavaScriptEnabled(true);

// Enable DOM storage
settings.setDomStorageEnabled(true);

Copy link

Copilot AI Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JavaScript + DOM storage are enabled for remote content without tightening other surfaces; consider explicitly disabling file and content access (settings.setAllowFileAccess(false); settings.setAllowContentAccess(false);) and enabling Safe Browsing (if API >= 26) to reduce attack surface.

Suggested change
// Disable file and content access for security
settings.setAllowFileAccess(false);
settings.setAllowContentAccess(false);
// Enable Safe Browsing if API >= 26
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
WebView.enableSafeBrowsing(mWebView.getContext());
settings.setSafeBrowsingEnabled(true);
}

Copilot uses AI. Check for mistakes.
// Disable file and content access for security
settings.setAllowFileAccess(false);
settings.setAllowContentAccess(false);

// Enable Safe Browsing if API >= 26
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
settings.setSafeBrowsingEnabled(true);
}

// Enable responsive layout
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);

// Enable zoom
settings.setSupportZoom(true);
settings.setBuiltInZoomControls(true);
settings.setDisplayZoomControls(false);

// Set cache mode
settings.setCacheMode(WebSettings.LOAD_DEFAULT);

// Set WebViewClient to handle navigation
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
// Let the WebView handle the navigation
return false;
}

@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
mProgressBar.setVisibility(View.VISIBLE);
}

@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);

// Inject CSS to ensure proper theme is applied
String theme = DarkModelUtils.isDarkMode() ? "dark" : "light";
String js = "javascript:(function() { " +
"document.documentElement.setAttribute('data-theme', '" + theme + "'); " +
"})()";
mWebView.loadUrl(js);
}
});

// Set WebChromeClient for progress updates
mWebView.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
mProgressBar.setProgress(newProgress);
if (newProgress == 100) {
mProgressBar.setVisibility(View.GONE);
}
}
Comment on lines +141 to +148
Copy link

Copilot AI Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Progress bar visibility is controlled in both onPageFinished and onProgressChanged leading to duplicated logic; consolidate visibility handling (e.g., rely solely on WebChromeClient progress events) to reduce redundancy.

Copilot uses AI. Check for mistakes.
});
}

@Override
public void onBackPressed() {
// Handle back navigation in WebView
if (mWebView.canGoBack()) {
mWebView.goBack();
} else {
super.onBackPressed();
}
}

@Override
protected void onDestroy() {
if (mWebView != null) {
mWebView.clearHistory();
mWebView.clearCache(false);
mWebView.loadUrl("about:blank");
mWebView.pauseTimers();
mWebView.destroy();
}
super.onDestroy();
}
}
21 changes: 21 additions & 0 deletions app/src/main/res/layout/activity_vshare_web.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent">

<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<ProgressBar
android:id="@+id/progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_gravity="top"
android:progressTint="@color/colorAccent"
android:visibility="gone" />

</FrameLayout>
Loading