Skip to content
Open
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
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ android {
dependenciesInfo {
includeInApk = false
}
compileSdk 35
compileSdk 36
splits {
abi {
enable true
Expand Down Expand Up @@ -55,7 +55,7 @@ android {
defaultConfig {
applicationId "com.cylonid.nativealpha"
minSdkVersion 28
targetSdkVersion 35
targetSdkVersion 36
versionCode 1520
versionName "1.5.2"

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
android:parentActivityName=".MainActivity"
android:icon="@mipmap/native_alpha"
android:roundIcon="@mipmap/native_alpha"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme.News">
</activity>

<activity
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/cylonid/nativealpha/AboutActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ import com.mikepenz.aboutlibraries.LibsBuilder
import mehdi.sakout.aboutpage.AboutPage
import mehdi.sakout.aboutpage.Element
import java.time.Year
import com.cylonid.nativealpha.util.WindowInsetsUtils

class AboutActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

val baseBinding = ActivityToolbarBaseBinding.inflate(layoutInflater)
setContentView(baseBinding.root)
WindowInsetsUtils.applyAsPadding(this, false)

baseBinding.activityContent.addView(generateAboutPageView())

Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/cylonid/nativealpha/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.cylonid.nativealpha.util.Const
import com.cylonid.nativealpha.util.EntryPointUtils.entryPointReached
import com.google.android.material.floatingactionbutton.FloatingActionButton
import io.github.edsuns.adfilter.AdFilter
import com.cylonid.nativealpha.util.WindowInsetsUtils


class MainActivity : AppCompatActivity() {
Expand All @@ -31,6 +32,7 @@ class MainActivity : AppCompatActivity() {
setTheme(R.style.AppTheme)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
WindowInsetsUtils.applyAsPadding(this, false)
webAppListFragment =
supportFragmentManager.findFragmentById(R.id.fragment_container_view) as WebAppListFragment
entryPointReached(this)
Expand Down
52 changes: 33 additions & 19 deletions app/src/main/java/com/cylonid/nativealpha/WebViewActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import android.widget.PopupMenu;
import android.widget.ProgressBar;

import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
Expand Down Expand Up @@ -70,6 +71,7 @@
import com.cylonid.nativealpha.util.NotificationUtils;
import com.cylonid.nativealpha.util.Utility;
import com.cylonid.nativealpha.util.WebViewLauncher;
import com.cylonid.nativealpha.util.WindowInsetsUtils;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.snackbar.Snackbar;

Expand Down Expand Up @@ -167,6 +169,9 @@ private void setupWebView() {
}

setContentView(R.layout.full_webview);
if (webapp.isShowFullscreen()) WindowInsetsUtils.applyKeyboardPadding(this);
else WindowInsetsUtils.applyAsPadding(this);
getOnBackPressedDispatcher().addCallback(this, backCallback);

if(webapp.isKeepAwake()) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Expand Down Expand Up @@ -358,7 +363,7 @@ public boolean onTouch(View v, MotionEvent event) {
WebViewLauncher.startWebView(DataManager.getInstance().getSuccessor(webappID), WebViewActivity.this);
finish();
} else if (DataManager.getInstance().getSettings().isTwoFingerMultitouch())
onBackPressed();
backCallback.handleOnBackPressed();

}
return true;
Expand All @@ -382,6 +387,13 @@ public boolean onTouch(View v, MotionEvent event) {
});
}

private void matchBarsToPage() {
wv.evaluateJavascript("(function(){function opaque(v){var m=v&&v.match(/^rgba?\\(([^)]+)\\)/);if(!m)return false;var p=m[1].split(/[,\\/\\s]+/).filter(Boolean);return p.length<4||parseFloat(p[3])>=0.5;}var e=document.body||document.documentElement,c=\"\";while(e){var v=getComputedStyle(e).backgroundColor;if(opaque(v)){c=v;break;}e=e.parentElement;}var m=document.querySelector('meta[name=\"theme-color\"]');return ((m&&m.content)||\"\")+\"|\"+c;})()", value -> {
String[] colors = value.split("\\|", -1);
WindowInsetsUtils.applyBarColors(this, colors[0], colors.length > 1 ? colors[1] : null);
});
}

@SuppressLint("RequiresFeature")
private void setDarkModeIfNeeded() {
if (!BuildConfig.FLAVOR.contains("extended")) {
Expand Down Expand Up @@ -464,7 +476,7 @@ private void showWebViewPopupMenu() {
wv.goForward();
return true;
case R.id.cmItemBack:
onBackPressed();
backCallback.handleOnBackPressed();
return true;
case R.id.cmItemReload:
wv.reload();
Expand Down Expand Up @@ -513,25 +525,26 @@ public void onConfigurationChanged(@NonNull Configuration newConfig) {
this.setDarkModeIfNeeded();
}

@Override
public void onBackPressed() {
WebApp webapp = DataManager.getInstance().getWebApp(webappID);

if(wv.canGoBack()) {
wv.goBack();
return;
}
private final OnBackPressedCallback backCallback = new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
WebApp webapp = DataManager.getInstance().getWebApp(webappID);

if(quitOnNextBackpress) {
quitOnNextBackpress = false;
moveTaskToBack(true);
return;
}
if (wv.canGoBack()) {
wv.goBack();
return;
}

loadURL(wv, webapp.getBaseUrl());
quitOnNextBackpress = true;
if (quitOnNextBackpress) {
quitOnNextBackpress = false;
moveTaskToBack(true);
return;
}

}
loadURL(wv, webapp.getBaseUrl());
quitOnNextBackpress = true;
}
};

@Override
protected void onResume() {
Expand Down Expand Up @@ -646,7 +659,6 @@ private void showSystemBars() {
if(webapp.isShowFullscreen()) return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

getWindow().setDecorFitsSystemWindows(true);
WindowInsetsController controller = getWindow().getInsetsController();
if (controller != null) {
controller.show(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars());
Expand Down Expand Up @@ -896,8 +908,10 @@ public void onPageFinished(WebView view, String url) {
if(url.equals("about:blank")) {
String langExtension = LocaleUtils.getFileEnding();
wv.loadUrl("file:///android_asset/errorSite/error_" + langExtension + ".html");
return;
}
wv.evaluateJavascript("document.addEventListener(\"visibilitychange\",function (event) {event.stopImmediatePropagation();},true);", null);
if (!webapp.isShowFullscreen()) matchBarsToPage();
super.onPageFinished(view, url);
}

Expand Down
124 changes: 124 additions & 0 deletions app/src/main/java/com/cylonid/nativealpha/util/WindowInsetsUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package com.cylonid.nativealpha.util

import android.app.Activity
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.ColorFilter
import android.graphics.Paint
import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
import android.os.Build
import android.view.View
import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import com.google.android.material.R
import com.google.android.material.color.MaterialColors

object WindowInsetsUtils {

private val INSET_TYPES = WindowInsetsCompat.Type.systemBars() or
WindowInsetsCompat.Type.displayCutout() or
WindowInsetsCompat.Type.ime()

private val RGB = Regex("""rgba?\((\d+)[,\s]+(\d+)[,\s]+(\d+)(?:[,/\s]+([\d.]+))?\)""")

/**
* Pads the content view by the insets it handles and reports those as zero, so that a WebView
* further down does not pad them twice. Pass [includeTop] = false to leave the top inset to a
* fitsSystemWindows app bar drawing behind the status bar.
*/
@JvmStatic
@JvmOverloads
fun applyAsPadding(
activity: Activity,
includeTop: Boolean = true,
types: Int = INSET_TYPES,
) {
WindowCompat.setDecorFitsSystemWindows(activity.window, false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
activity.window.isNavigationBarContrastEnforced = false
}
ViewCompat.setOnApplyWindowInsetsListener(activity.findViewById(android.R.id.content)) { v, windowInsets ->
val insets = windowInsets.getInsets(types)
v.setPadding(insets.left, if (includeTop) insets.top else 0, insets.right, insets.bottom)
val unhandled = if (includeTop) Insets.NONE else Insets.of(0, insets.top, 0, 0)
WindowInsetsCompat.Builder(windowInsets).setInsets(types, unhandled).build()
}
}

@JvmStatic
fun applyKeyboardPadding(activity: Activity) {
applyAsPadding(activity, types = WindowInsetsCompat.Type.ime())
}

/** Paints each area kept free for the system bars and adapts the icon colour. */
@JvmStatic
fun applyBarColors(activity: Activity, topCss: String?, bottomCss: String?) {
val content = activity.findViewById<View>(android.R.id.content)
val parsedBottom = parseCssColor(bottomCss)
val top = parseCssColor(topCss) ?: parsedBottom
if (top == null) {
content.background = null
val surface = MaterialColors.getColor(content, R.attr.colorSurface, Color.WHITE)
setBarAppearance(activity, surface, surface)
return
}
val bottom = parsedBottom ?: top
(content.background as? BarBackground)?.setColors(top, bottom)
?: run { content.background = BarBackground(top, bottom, content) }
setBarAppearance(activity, top, bottom)
}

private fun setBarAppearance(activity: Activity, top: Int, bottom: Int) {
WindowInsetsControllerCompat(activity.window, activity.window.decorView).apply {
isAppearanceLightStatusBars = MaterialColors.isColorLight(top)
isAppearanceLightNavigationBars = MaterialColors.isColorLight(bottom)
}
}

private class BarBackground(
private var top: Int,
private var bottom: Int,
private val host: View,
) : Drawable() {
private val paint = Paint()

fun setColors(top: Int, bottom: Int) {
if (top == this.top && bottom == this.bottom) return
this.top = top
this.bottom = bottom
invalidateSelf()
}

override fun draw(canvas: Canvas) {
val b = bounds
paint.color = top
canvas.drawRect(b.left.toFloat(), b.top.toFloat(), b.right.toFloat(), (b.top + host.paddingTop).toFloat(), paint)
paint.color = bottom
canvas.drawRect(b.left.toFloat(), (b.bottom - host.paddingBottom).toFloat(), b.right.toFloat(), b.bottom.toFloat(), paint)
}

override fun setAlpha(alpha: Int) = Unit
override fun setColorFilter(colorFilter: ColorFilter?) = Unit
override fun getOpacity() = PixelFormat.TRANSLUCENT
}

private fun parseCssColor(value: String?): Int? {
val v = value?.trim { it == '"' || it.isWhitespace() }?.takeIf { it.isNotEmpty() } ?: return null
RGB.matchEntire(v)?.let { m ->
if ((m.groupValues[4].toFloatOrNull() ?: 1f) < 0.5f) return null
val rgb = (1..3).map { m.groupValues[it].toIntOrNull() ?: return null }
if (rgb.any { it > 255 }) return null
return Color.rgb(rgb[0], rgb[1], rgb[2])
}
val hex = if (v.length == 4 && v[0] == '#') {
v.drop(1).map { "$it$it" }.joinToString(separator = "", prefix = "#")
} else {
v
}
return runCatching { Color.parseColor(hex) }.getOrNull()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.cylonid.nativealpha.BuildConfig
import com.cylonid.nativealpha.databinding.NewsActivityBinding
import com.cylonid.nativealpha.model.DataManager
import com.cylonid.nativealpha.util.LocaleUtils
import com.cylonid.nativealpha.util.WindowInsetsUtils


class NewsActivity : AppCompatActivity(), View.OnTouchListener {
Expand All @@ -38,6 +39,7 @@ class NewsActivity : AppCompatActivity(), View.OnTouchListener {
binding = NewsActivityBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
WindowInsetsUtils.applyAsPadding(this)

binding.newsContent.settings.javaScriptEnabled = true
binding.newsContent.isLongClickable = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.activity.addCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.viewbinding.ViewBinding
import com.cylonid.nativealpha.databinding.ActivityToolbarBaseBinding
import com.cylonid.nativealpha.util.WindowInsetsUtils

abstract class ToolbarBaseActivity<VB : ViewBinding> : AppCompatActivity() {

Expand All @@ -21,6 +22,7 @@ abstract class ToolbarBaseActivity<VB : ViewBinding> : AppCompatActivity() {

val baseBinding = ActivityToolbarBaseBinding.inflate(layoutInflater)
setContentView(baseBinding.root)
WindowInsetsUtils.applyAsPadding(this, false)

_binding = inflateBinding(layoutInflater)
baseBinding.activityContent.addView(_binding.root)
Expand Down
8 changes: 6 additions & 2 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity">

<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:background="@color/colorSignature"
android:fitsSystemWindows="true"
app:liftOnScroll="false">

<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
app:logo="@mipmap/native_alpha_white"
app:titleTextColor="@android:color/white"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorSignature" />
android:theme="@style/ThemeOverlay.AppTheme.Toolbar" />

</com.google.android.material.appbar.AppBarLayout>

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/layout/fragment_adblock_list.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
app:behind_swiped_item_icon="@drawable/ic_delete_black_24dp"
app:behind_swiped_item_bg_color="@color/swipe_action_negative"
app:behind_swiped_item_bg_color="?attr/colorErrorContainer"
app:item_layout="@layout/adblock_list_item"
app:swiped_item_opacity_fades_on_swiping="true"
app:behind_swiped_item_icon_margin="@dimen/margin_swipe_icon"
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/res/layout/fragment_web_app_list.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
android:layout_height="match_parent"
app:item_layout="@layout/web_app_list_item"
app:behind_swiped_item_icon="@drawable/ic_delete_black_24dp"
app:behind_swiped_item_bg_color="@color/swipe_action_negative"
app:behind_swiped_item_bg_color_secondary="@color/swipe_action_neutral"
app:behind_swiped_item_bg_color="?attr/colorErrorContainer"
app:behind_swiped_item_bg_color_secondary="?attr/colorTertiaryContainer"
app:behind_swiped_item_icon_secondary="@drawable/ic_settings_black_24dp"
app:behind_swiped_item_icon_margin="@dimen/margin_swipe_icon"
app:swiped_item_opacity_fades_on_swiping="true"
Expand Down
Loading