From 962b47b4e7284c948982dbfbba4b66f3693694d3 Mon Sep 17 00:00:00 2001 From: Gray Zhang Date: Fri, 17 Oct 2025 11:14:31 +0800 Subject: [PATCH 1/8] feat: improve Vshare WebView with intent URL support and status bar padding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit addresses two UX issues in the Vshare WebView: 1. **Intent URL Support**: Fixed handling of intent:// URLs (e.g., Google Play Store links) - Added handleUrlLoading() method to intercept and process special URL schemes - Supports intent://, market://, and other app-specific schemes (mailto:, tel:, etc.) - Includes fallback mechanisms for better user experience - Displays appropriate error messages when apps are not available 2. **Status Bar Padding**: Added paddingTop to prevent content from being hidden - Added android:fitsSystemWindows="true" to WebView - Ensures content is properly displayed below the status bar in edge-to-edge mode Changes made: - VshareWebActivity.java: Added URL scheme handling logic with comprehensive fallback support - activity_vshare_web.xml: Added fitsSystemWindows attribute to WebView 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../v2er/module/vshare/VshareWebActivity.java | 95 ++++++++++++++++++- .../main/res/layout/activity_vshare_web.xml | 3 +- 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java b/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java index 5a97d74d..b63e3927 100644 --- a/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java +++ b/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java @@ -1,10 +1,13 @@ package me.ghui.v2er.module.vshare; import android.annotation.SuppressLint; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; +import android.net.Uri; import android.os.Bundle; +import android.util.Log; import android.view.View; import android.webkit.WebChromeClient; import android.webkit.WebResourceRequest; @@ -12,6 +15,7 @@ import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.ProgressBar; +import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; @@ -26,6 +30,7 @@ */ public class VshareWebActivity extends AppCompatActivity { + private static final String TAG = "VshareWebActivity"; private static final String VSHARE_BASE_URL = "https://v2er.app/vshare"; @BindView(R.id.webview) @@ -114,8 +119,12 @@ private void setupWebView() { mWebView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { - // Let the WebView handle the navigation - return false; + return handleUrlLoading(request.getUrl().toString()); + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + return handleUrlLoading(url); } @Override @@ -149,6 +158,88 @@ public void onProgressChanged(WebView view, int newProgress) { }); } + /** + * Handle URL loading for WebView + * Returns true if the URL was handled externally, false if WebView should load it + */ + private boolean handleUrlLoading(String url) { + if (url == null) { + return false; + } + + Uri uri = Uri.parse(url); + String scheme = uri.getScheme(); + + // Handle intent:// URLs (e.g., Google Play Store links) + if ("intent".equals(scheme)) { + try { + Intent intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); + + // Check if there's an app that can handle this intent + if (getPackageManager().resolveActivity(intent, 0) != null) { + startActivity(intent); + return true; + } + + // Fallback: Try to open the browser_fallback_url if available + String fallbackUrl = intent.getStringExtra("browser_fallback_url"); + if (fallbackUrl != null) { + mWebView.loadUrl(fallbackUrl); + return true; + } + + // Last resort: Try to open in Google Play if it's a Play Store intent + String packageName = intent.getPackage(); + if (packageName != null) { + Intent marketIntent = new Intent(Intent.ACTION_VIEW, + Uri.parse("market://details?id=" + packageName)); + marketIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + if (getPackageManager().resolveActivity(marketIntent, 0) != null) { + startActivity(marketIntent); + return true; + } + } + } catch (Exception e) { + Log.e(TAG, "Error handling intent URL: " + url, e); + Toast.makeText(this, "Unable to open app", Toast.LENGTH_SHORT).show(); + } + return true; + } + + // Handle market:// URLs (Google Play Store) + if ("market".equals(scheme)) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + return true; + } catch (ActivityNotFoundException e) { + Log.e(TAG, "Google Play Store not found", e); + // Fallback to web version + String webUrl = url.replace("market://", "https://play.google.com/store/apps/"); + mWebView.loadUrl(webUrl); + return true; + } + } + + // Handle other app-specific schemes (e.g., mailto:, tel:, etc.) + if (!"http".equals(scheme) && !"https".equals(scheme)) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + return true; + } catch (ActivityNotFoundException e) { + Log.e(TAG, "No app found to handle scheme: " + scheme, e); + Toast.makeText(this, "No app found to open this link", Toast.LENGTH_SHORT).show(); + return true; + } + } + + // Let WebView handle normal http/https URLs + return false; + } + @Override public void onBackPressed() { // Handle back navigation in WebView diff --git a/app/src/main/res/layout/activity_vshare_web.xml b/app/src/main/res/layout/activity_vshare_web.xml index 8b509bd5..0dce5ac5 100644 --- a/app/src/main/res/layout/activity_vshare_web.xml +++ b/app/src/main/res/layout/activity_vshare_web.xml @@ -7,7 +7,8 @@ + android:layout_height="match_parent" + android:fitsSystemWindows="true" /> Date: Fri, 17 Oct 2025 11:18:44 +0800 Subject: [PATCH 2/8] fix: use explicit paddingTop for WebView status bar spacing --- app/src/main/res/layout/activity_vshare_web.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_vshare_web.xml b/app/src/main/res/layout/activity_vshare_web.xml index 0dce5ac5..11559464 100644 --- a/app/src/main/res/layout/activity_vshare_web.xml +++ b/app/src/main/res/layout/activity_vshare_web.xml @@ -8,7 +8,7 @@ android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" - android:fitsSystemWindows="true" /> + android:paddingTop="30dp" /> Date: Fri, 17 Oct 2025 11:34:57 +0800 Subject: [PATCH 3/8] fix: properly handle status bar padding using WindowInsets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous approach using static paddingTop in XML didn't work because the activity uses SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN for edge-to-edge layout. This commit fixes the issue by: 1. Using OnApplyWindowInsetsListener to dynamically get the status bar height 2. Programmatically applying it as padding to the WebView 3. Including fallback for older API levels using resource identifier This ensures content is properly displayed below the status bar on all devices and screen configurations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../v2er/module/vshare/VshareWebActivity.java | 29 +++++++++++++++++++ .../main/res/layout/activity_vshare_web.xml | 3 +- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java b/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java index b63e3927..ac3d8544 100644 --- a/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java +++ b/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java @@ -72,6 +72,23 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_vshare_web); ButterKnife.bind(this); + // Apply window insets to WebView for proper status bar padding + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT_WATCH) { + mWebView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { + @Override + public android.view.WindowInsets onApplyWindowInsets(View v, android.view.WindowInsets insets) { + // Apply top inset (status bar height) as padding + int topInset = insets.getSystemWindowInsetTop(); + mWebView.setPadding(0, topInset, 0, 0); + return insets.consumeSystemWindowInsets(); + } + }); + } else { + // Fallback for older API levels - estimate status bar height + int statusBarHeight = getStatusBarHeight(); + mWebView.setPadding(0, statusBarHeight, 0, 0); + } + setupWebView(); // Compute URL with theme parameter based on current app theme @@ -240,6 +257,18 @@ private boolean handleUrlLoading(String url) { return false; } + /** + * Get status bar height for older API levels + */ + private int getStatusBarHeight() { + int result = 0; + int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resourceId > 0) { + result = getResources().getDimensionPixelSize(resourceId); + } + return result; + } + @Override public void onBackPressed() { // Handle back navigation in WebView diff --git a/app/src/main/res/layout/activity_vshare_web.xml b/app/src/main/res/layout/activity_vshare_web.xml index 11559464..8b509bd5 100644 --- a/app/src/main/res/layout/activity_vshare_web.xml +++ b/app/src/main/res/layout/activity_vshare_web.xml @@ -7,8 +7,7 @@ + android:layout_height="match_parent" /> Date: Fri, 17 Oct 2025 11:51:42 +0800 Subject: [PATCH 4/8] refactor: make VshareWebActivity extend BaseActivity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit refactors VshareWebActivity to inherit from BaseActivity instead of AppCompatActivity, providing better integration with the app's architecture. Benefits: 1. Automatic theme handling via reloadMode() - activity recreates on theme change 2. EventBus integration for day/night mode events 3. Consistent edge-to-edge layout handling 4. Access to base lifecycle management and utilities 5. Disabled slide-back gesture for fullscreen WebView experience Changes: - Extended BaseActivity - Implemented attachLayoutRes() to provide layout - Implemented reloadMode() for theme switching support - Overridden supportSlideBack() to disable swipe-back - Moved initialization logic from onCreate() to init() - Removed manual ButterKnife binding (handled by BaseActivity) The WebView functionality remains unchanged, including: - Intent URL handling for external apps - WindowInsets-based status bar padding - Theme-aware content loading 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../v2er/module/vshare/VshareWebActivity.java | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java b/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java index ac3d8544..0391f4f8 100644 --- a/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java +++ b/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java @@ -17,18 +17,17 @@ import android.widget.ProgressBar; import android.widget.Toast; -import androidx.appcompat.app.AppCompatActivity; - import butterknife.BindView; -import butterknife.ButterKnife; import me.ghui.v2er.R; +import me.ghui.v2er.module.base.BaseActivity; +import me.ghui.v2er.module.base.BaseContract; import me.ghui.v2er.util.DarkModelUtils; /** * Fullscreen WebView Activity for displaying vshare page * with automatic theme adaptation */ -public class VshareWebActivity extends AppCompatActivity { +public class VshareWebActivity extends BaseActivity { private static final String TAG = "VshareWebActivity"; private static final String VSHARE_BASE_URL = "https://v2er.app/vshare"; @@ -45,18 +44,29 @@ public static void open(Context context) { } @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected int attachLayoutRes() { + return R.layout.activity_vshare_web; + } - // Hide action bar if present - if (getSupportActionBar() != null) { - getSupportActionBar().hide(); - } + @Override + protected void reloadMode(int mode) { + // Recreate activity to apply new theme + recreate(); + } + + @Override + protected boolean supportSlideBack() { + // Disable slide back for fullscreen WebView + return false; + } - // Set SystemUI flags to match MainActivity's edge-to-edge behavior + @Override + protected void init() { + super.init(); + + // Apply fullscreen flags for edge-to-edge WebView View decorView = getWindow().getDecorView(); - int systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + int systemUiVisibility = decorView.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; // Set status bar icon color based on theme @@ -69,9 +79,6 @@ protected void onCreate(Bundle savedInstanceState) { decorView.setSystemUiVisibility(systemUiVisibility); - setContentView(R.layout.activity_vshare_web); - ButterKnife.bind(this); - // Apply window insets to WebView for proper status bar padding if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT_WATCH) { mWebView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { @@ -290,4 +297,4 @@ protected void onDestroy() { } super.onDestroy(); } -} \ No newline at end of file +} From 59072201fe31d1e0eb35f763dd0de32029549d60 Mon Sep 17 00:00:00 2001 From: Gray Zhang Date: Fri, 17 Oct 2025 11:54:29 +0800 Subject: [PATCH 5/8] feat: hide toolbar in VshareWebActivity for fullscreen experience MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Override attachToolbar() to return null, which tells BaseActivity not to create a toolbar for this activity. This provides a true fullscreen WebView experience without any app chrome. Implementation follows the existing pattern used in TwoStepLoginActivity and other fullscreen activities in the codebase. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../me/ghui/v2er/module/vshare/VshareWebActivity.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java b/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java index 0391f4f8..a0c8a961 100644 --- a/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java +++ b/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java @@ -17,11 +17,14 @@ import android.widget.ProgressBar; import android.widget.Toast; +import androidx.annotation.Nullable; + import butterknife.BindView; import me.ghui.v2er.R; import me.ghui.v2er.module.base.BaseActivity; import me.ghui.v2er.module.base.BaseContract; import me.ghui.v2er.util.DarkModelUtils; +import me.ghui.v2er.widget.BaseToolBar; /** * Fullscreen WebView Activity for displaying vshare page @@ -48,6 +51,13 @@ protected int attachLayoutRes() { return R.layout.activity_vshare_web; } + @Nullable + @Override + protected BaseToolBar attachToolbar() { + // Return null to hide the toolbar for fullscreen WebView experience + return null; + } + @Override protected void reloadMode(int mode) { // Recreate activity to apply new theme From a54021bf161c1ffe8aeef8a01e56d0a998417db3 Mon Sep 17 00:00:00 2001 From: Gray Zhang Date: Fri, 17 Oct 2025 11:56:54 +0800 Subject: [PATCH 6/8] fix: add fitsSystemWindows to WebView to properly handle status bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added android:fitsSystemWindows="true" to the WebView in the layout XML to work in conjunction with the programmatic WindowInsets handling. This ensures the WebView content is not obscured by the status bar, providing proper spacing at the top of the page. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/src/main/res/layout/activity_vshare_web.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_vshare_web.xml b/app/src/main/res/layout/activity_vshare_web.xml index 8b509bd5..0dce5ac5 100644 --- a/app/src/main/res/layout/activity_vshare_web.xml +++ b/app/src/main/res/layout/activity_vshare_web.xml @@ -7,7 +7,8 @@ + android:layout_height="match_parent" + android:fitsSystemWindows="true" /> Date: Fri, 17 Oct 2025 11:58:54 +0800 Subject: [PATCH 7/8] fix: use layout_marginTop instead of WindowInsets for WebView spacing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplified the status bar spacing approach: - Added android:layout_marginTop="30dp" to WebView in XML layout - Removed WindowInsets listener code (was not working reliably) - Removed getStatusBarHeight() helper method (no longer needed) This provides a simpler, more predictable way to prevent content from being obscured by the status bar, using a fixed margin at the top. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../v2er/module/vshare/VshareWebActivity.java | 29 ------------------- .../main/res/layout/activity_vshare_web.xml | 2 +- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java b/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java index a0c8a961..64651844 100644 --- a/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java +++ b/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java @@ -89,23 +89,6 @@ protected void init() { decorView.setSystemUiVisibility(systemUiVisibility); - // Apply window insets to WebView for proper status bar padding - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT_WATCH) { - mWebView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { - @Override - public android.view.WindowInsets onApplyWindowInsets(View v, android.view.WindowInsets insets) { - // Apply top inset (status bar height) as padding - int topInset = insets.getSystemWindowInsetTop(); - mWebView.setPadding(0, topInset, 0, 0); - return insets.consumeSystemWindowInsets(); - } - }); - } else { - // Fallback for older API levels - estimate status bar height - int statusBarHeight = getStatusBarHeight(); - mWebView.setPadding(0, statusBarHeight, 0, 0); - } - setupWebView(); // Compute URL with theme parameter based on current app theme @@ -274,18 +257,6 @@ private boolean handleUrlLoading(String url) { return false; } - /** - * Get status bar height for older API levels - */ - private int getStatusBarHeight() { - int result = 0; - int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); - if (resourceId > 0) { - result = getResources().getDimensionPixelSize(resourceId); - } - return result; - } - @Override public void onBackPressed() { // Handle back navigation in WebView diff --git a/app/src/main/res/layout/activity_vshare_web.xml b/app/src/main/res/layout/activity_vshare_web.xml index 0dce5ac5..14caccfe 100644 --- a/app/src/main/res/layout/activity_vshare_web.xml +++ b/app/src/main/res/layout/activity_vshare_web.xml @@ -8,7 +8,7 @@ android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" - android:fitsSystemWindows="true" /> + android:layout_marginTop="30dp" /> Date: Fri, 17 Oct 2025 12:11:53 +0800 Subject: [PATCH 8/8] refactor: dynamically set WebView top margin based on status bar height MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed from static layout_marginTop to programmatically setting the margin based on the actual status bar height. Changes: - Removed android:layout_marginTop from XML layout - Added applyStatusBarMargin() method to set margin programmatically - Added getStatusBarHeight() to retrieve actual status bar height - Applied margin in init() after ButterKnife binds the views This ensures the WebView properly adapts to different devices and screen configurations, providing consistent spacing below the status bar. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../v2er/module/vshare/VshareWebActivity.java | 31 +++++++++++++++++++ .../main/res/layout/activity_vshare_web.xml | 3 +- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java b/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java index 64651844..873224cf 100644 --- a/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java +++ b/app/src/main/java/me/ghui/v2er/module/vshare/VshareWebActivity.java @@ -9,6 +9,8 @@ import android.os.Bundle; import android.util.Log; import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; import android.webkit.WebChromeClient; import android.webkit.WebResourceRequest; import android.webkit.WebSettings; @@ -89,6 +91,9 @@ protected void init() { decorView.setSystemUiVisibility(systemUiVisibility); + // Set WebView top margin to status bar height + applyStatusBarMargin(); + setupWebView(); // Compute URL with theme parameter based on current app theme @@ -175,6 +180,32 @@ public void onProgressChanged(WebView view, int newProgress) { }); } + /** + * Apply status bar height as top margin to WebView + */ + private void applyStatusBarMargin() { + int statusBarHeight = getStatusBarHeight(); + if (statusBarHeight > 0) { + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mWebView.getLayoutParams(); + if (params instanceof FrameLayout.LayoutParams) { + params.topMargin = statusBarHeight; + mWebView.setLayoutParams(params); + } + } + } + + /** + * Get status bar height dynamically + */ + private int getStatusBarHeight() { + int result = 0; + int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resourceId > 0) { + result = getResources().getDimensionPixelSize(resourceId); + } + return result; + } + /** * Handle URL loading for WebView * Returns true if the URL was handled externally, false if WebView should load it diff --git a/app/src/main/res/layout/activity_vshare_web.xml b/app/src/main/res/layout/activity_vshare_web.xml index 14caccfe..8b509bd5 100644 --- a/app/src/main/res/layout/activity_vshare_web.xml +++ b/app/src/main/res/layout/activity_vshare_web.xml @@ -7,8 +7,7 @@ + android:layout_height="match_parent" />