This commit is contained in:
coco
2026-07-03 16:23:31 +08:00
commit 7a4fb0e6ae
1979 changed files with 101570 additions and 0 deletions
@@ -0,0 +1 @@
/build
@@ -0,0 +1,95 @@
def isBuildModule = rootProject.ext.module.isBuildModule
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-parcelize'
apply plugin: 'com.google.dagger.hilt.android'
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode rootProject.ext.android.versionCode
versionName rootProject.ext.android.versionName
multiDexEnabled true
javaCompileOptions {
annotationProcessorOptions {
arguments += [
"room.schemaLocation":"$projectDir/schemas".toString(),
"room.incremental":"true",
"room.expandProjection":"true",
AROUTER_MODULE_NAME: project.getName()
]
}
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
buildFeatures {
viewBinding true
}
}
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
generateStubs = true
useBuildCache = true
javacOptions {
option("-Xmaxerrs", 500)
}
}
dependencies {
implementation project(":common:common-base")
implementation project(":common:common-service")
kapt rootProject.ext.compiler["arouterCompiler"]
if (Boolean.valueOf(isBuildModule)) {
implementation project(":modules:module-collect")
}
compileOnly(rootProject.ext.jetpack["hilt"])
kapt rootProject.ext.compiler["hiltAndroidCompiler"]
}
// 发布module到maven仓库
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.17.0'
}
}
allprojects {
plugins.withId("com.vanniktech.maven.publish") {
mavenPublish {
sonatypeHost = "S01"
}
}
}
apply plugin: "com.vanniktech.maven.publish"
@@ -0,0 +1,31 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep public class com.alibaba.android.arouter.facade.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
# 如果使用了 byType 的方式获取 Service,需添加下面规则,保护接口
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider
# 如果使用了 单类注入,即不定义接口实现 IProvider,需添加下面规则,保护实现
# -keep class * implements com.alibaba.android.arouter.facade.template.IProvider
@@ -0,0 +1,24 @@
package com.bbgo.module_content
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.bbgo.module_content.test", appContext.packageName)
}
}
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.bbgo.module_content">
<application>
<activity android:name=".ui.ContentActivity"/>
</application>
</manifest>
@@ -0,0 +1,39 @@
package com.bbgo.module_content.ext
import android.app.Activity
import android.view.ViewGroup
import android.webkit.WebView
import com.bbgo.module_content.R
import com.just.agentweb.AgentWeb
import com.just.agentweb.DefaultWebClient
import com.just.agentweb.WebChromeClient
import com.just.agentweb.WebViewClient
/**
* Created by chenxz on 2018/4/22.
*/
/**
* getAgentWeb
*/
fun String.getAgentWeb(
activity: Activity,
webContent: ViewGroup,
layoutParams: ViewGroup.LayoutParams,
webView: WebView,
webViewClient: WebViewClient?,
webChromeClient: WebChromeClient?,
indicatorColor: Int
): AgentWeb = AgentWeb.with(activity)//传入Activity or Fragment
.setAgentWebParent(webContent, 1, layoutParams)//传入AgentWeb 的父控件
.useDefaultIndicator(indicatorColor, 2)// 使用默认进度条
.setWebView(webView)
.setWebViewClient(webViewClient)
.setWebChromeClient(webChromeClient)
.setMainFrameErrorView(R.layout.agentweb_error_page, -1)
.setSecurityType(AgentWeb.SecurityType.STRICT_CHECK)
.setOpenOtherPageWays(DefaultWebClient.OpenOtherPageWays.ASK)//打开其他应用时,弹窗咨询用户是否前往其他应用
.interceptUnkownUrl()
.createAgentWeb()//
.ready()
.go(this)
@@ -0,0 +1,252 @@
package com.bbgo.module_content.ui
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.KeyEvent
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.webkit.WebSettings
import android.webkit.WebView
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.alibaba.android.arouter.facade.annotation.Autowired
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import com.bbgo.common_base.base.BaseActivity
import com.bbgo.common_base.bus.BusKey
import com.bbgo.common_base.bus.LiveDataBus
import com.bbgo.common_base.constants.Constants
import com.bbgo.common_base.constants.RouterPath
import com.bbgo.common_base.event.MessageEvent
import com.bbgo.common_base.ext.showToast
import com.bbgo.common_base.util.AppUtil
import com.bbgo.common_base.util.SettingUtil
import com.bbgo.common_service.collect.CollectService
import com.bbgo.module_content.R
import com.bbgo.module_content.databinding.ActivityContentBinding
import com.bbgo.module_content.ext.getAgentWeb
import com.bbgo.module_content.webclient.WebClientFactory
import com.google.android.material.appbar.AppBarLayout
import com.just.agentweb.AgentWeb
import com.just.agentweb.NestedScrollAgentWebView
import com.just.agentweb.WebChromeClient
@Route(path = RouterPath.Content.PAGE_CONTENT)
class ContentActivity : BaseActivity<ActivityContentBinding>(){
private var mAgentWeb: AgentWeb? = null
@Autowired
lateinit var title: String
@Autowired
lateinit var url: String
@Autowired
lateinit var id: String
@Autowired
lateinit var position: String
@Autowired
lateinit var isCollect: String
@Autowired
lateinit var collectService: CollectService
private lateinit var menu: Menu
companion object {
fun start(context: Context?, position: Int, id: Int, title: String, url: String, bundle: Bundle? = null) {
Intent(context, ContentActivity::class.java).run {
putExtra(Constants.CONTENT_ID_KEY, id)
putExtra(Constants.CONTENT_TITLE_KEY, title)
putExtra(Constants.CONTENT_URL_KEY, url)
putExtra(Constants.POSITION, position)
context?.startActivity(this, bundle)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
initView()
}
private fun initView() {
ARouter.getInstance().inject(this)
initBus()
binding.actionBar.apply {
title = ""//getString(R.string.loading)
setSupportActionBar(binding.actionBar.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
binding.actionBar.tvTitle.apply {
text = getString(R.string.agentweb_loading)
visibility = View.VISIBLE
postDelayed({
binding.actionBar.tvTitle.isSelected = true
}, 2000)
}
initWebView()
}
/**
* 初始化 WebView
*/
private fun initWebView() {
val webView = NestedScrollAgentWebView(this)
val layoutParams = CoordinatorLayout.LayoutParams(-1, -1)
layoutParams.behavior = AppBarLayout.ScrollingViewBehavior()
mAgentWeb = url.getAgentWeb(
this,
binding.clMain,
layoutParams,
webView,
WebClientFactory.create(url),
mWebChromeClient,
SettingUtil.getColor())
//if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// WebView.setWebContentsDebuggingEnabled(true)
//}
mAgentWeb?.webCreator?.webView?.apply {
overScrollMode = WebView.OVER_SCROLL_NEVER
settings.domStorageEnabled = true
settings.javaScriptEnabled = true
settings.loadsImagesAutomatically = true
settings.useWideViewPort = true
settings.loadWithOverviewMode = true
settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
}
}
}
private val mWebChromeClient = object : WebChromeClient() {
override fun onReceivedTitle(view: WebView, title: String) {
super.onReceivedTitle(view, title)
binding.actionBar.tvTitle.text = title
}
}
private fun initBus() {
LiveDataBus.get().with(BusKey.COLLECT, MessageEvent::class.java).observe(this) {
handleCollect(it)
}
}
private fun handleCollect(event: MessageEvent) {
when (event.type) {
Constants.CollectType.UNKNOWN -> {
ARouter.getInstance().build(RouterPath.LoginRegister.PAGE_LOGIN).navigation()
}
else -> {
val menuItem = menu.findItem(R.id.action_like)
if (event.type == Constants.CollectType.COLLECT) {
showToast(getString(R.string.collect_success))
menuItem.title = getString(R.string.action_un_like)
isCollect = "true"
return
}
showToast(getString(R.string.cancel_collect_success))
menuItem.title = getString(R.string.action_like)
isCollect = "false"
}
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_content, menu)
this.menu = menu
val title = if (isCollect.toBoolean()) {
getString(R.string.action_un_like)
} else {
getString(R.string.action_like)
}
val menuItem = menu.findItem(R.id.action_like)
menuItem.title = title
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_share -> {
Intent().run {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, getString(
R.string.share_article_url,
getString(R.string.app_name), title, url
))
type = Constants.CONTENT_SHARE_TYPE
startActivity(Intent.createChooser(this, getString(R.string.action_share)))
}
return true
}
R.id.action_like -> {
if (AppUtil.isLogin) {
if (id == "-1") return true
if (isCollect.toBoolean()) {
collectService.unCollect(-1, position.toInt(), id.toInt())
} else {
collectService.collect(-1, position.toInt(), id.toInt())
}
} else {
ARouter.getInstance().build(RouterPath.LoginRegister.PAGE_LOGIN).navigation()
showToast(resources.getString(R.string.login_tint))
}
return true
}
R.id.action_browser -> {
Intent().run {
action = "android.intent.action.VIEW"
data = Uri.parse(url)
startActivity(this)
}
return true
}
}
return super.onOptionsItemSelected(item)
}
override fun onBackPressed() {
mAgentWeb?.let {
if (!it.back()) {
super.onBackPressed()
}
}
}
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (mAgentWeb?.handleKeyEvent(keyCode, event)!!) {
return true
}
return super.onKeyDown(keyCode, event)
}
override fun onResume() {
mAgentWeb?.webLifeCycle?.onResume()
super.onResume()
}
override fun onPause() {
mAgentWeb?.webLifeCycle?.onPause()
super.onPause()
}
override fun onDestroy() {
mAgentWeb?.webLifeCycle?.onDestroy()
super.onDestroy()
}
override fun inflateViewBinding() = ActivityContentBinding.inflate(layoutInflater)
}
@@ -0,0 +1,41 @@
package com.bbgo.module_content.ui
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.util.AttributeSet
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat
import com.bbgo.common_base.util.ColorUtil
import com.bbgo.common_base.util.SettingUtil
import com.bbgo.module_content.R
/**
* @author chenxz
* @date 2019/11/24
* @desc WebContainer
*/
class WebContainer @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
: CoordinatorLayout(context, attrs, defStyleAttr) {
private var mDarkTheme: Boolean = false
private var mMaskColor = Color.TRANSPARENT
init {
mDarkTheme = SettingUtil.getIsNightMode()
if (mDarkTheme) {
mMaskColor = ColorUtil.alphaColor(ContextCompat.getColor(getContext(),
R.color.mask_color
), 0.6f)
}
}
override fun dispatchDraw(canvas: Canvas) {
super.dispatchDraw(canvas)
if (mDarkTheme) {
canvas.drawColor(mMaskColor)
}
}
}
@@ -0,0 +1,20 @@
package com.bbgo.module_content.util
import okhttp3.OkHttpClient
import okhttp3.Request
object Wget {
fun get(url: String): String {
val client = OkHttpClient.Builder()
.build()
val request = Request.Builder()
.url(url)
.header("user-agent",
"Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3887.7 Mobile Safari/537.36")
.build()
val response = client.newCall(request).execute()
return response.body?.string() ?: ""
}
}
@@ -0,0 +1,95 @@
package com.bbgo.module_content.webclient
import android.graphics.Bitmap
import android.net.Uri
import android.net.http.SslError
import android.os.Build
import android.util.Log
import android.webkit.*
import androidx.annotation.RequiresApi
import com.just.agentweb.WebViewClient
/**
* @author chenxz
* @date 2019/11/24
* @desc BaseWebClient
*/
open class BaseWebClient : WebViewClient() {
protected val TAG = "BaseWebClient"
// 拦截的网址
private val blackHostList = arrayListOf(
"www.taobao.com",
"www.jd.com",
"yun.tuisnake.com",
"yun.lvehaisen.com",
"yun.tuitiger.com"
)
private fun isBlackHost(host: String): Boolean {
for (blackHost in blackHostList) {
if (blackHost == host) {
return true
}
}
return false
}
private fun shouldInterceptRequest(uri: Uri?): Boolean {
if (uri != null) {
val host = uri.host ?: ""
return isBlackHost(host)
}
return false
}
private fun shouldOverrideUrlLoading(uri: Uri?): Boolean {
if (uri != null) {
val host = uri.host ?: ""
return isBlackHost(host)
}
return false
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest?): WebResourceResponse? {
if (shouldInterceptRequest(request?.url)) {
return WebResourceResponse(null, null, null)
}
return super.shouldInterceptRequest(view, request)
}
override fun shouldInterceptRequest(view: WebView?, url: String?): WebResourceResponse? {
Log.e(TAG, "------------>>$url")
if (shouldInterceptRequest(Uri.parse(url))) {
return WebResourceResponse(null, null, null)
}
return super.shouldInterceptRequest(view, url)
}
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
return shouldOverrideUrlLoading(Uri.parse(url))
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
return shouldOverrideUrlLoading(request?.url)
}
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
Log.e(TAG, "onPageStarted---->>$url")
}
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
Log.e(TAG, "onPageFinished---->>$url")
}
override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
// super.onReceivedSslError(view, handler, error)
handler?.proceed()
}
}
@@ -0,0 +1,59 @@
package com.bbgo.module_content.webclient
import android.content.Context
import android.webkit.WebResourceResponse
import android.webkit.WebView
import com.bbgo.common_base.util.StringUtil
import com.bbgo.module_content.util.Wget
import java.io.ByteArrayInputStream
import java.util.regex.Pattern
/**
* @author chenxz
* @date 2019/11/24
* @desc JianShuWebClient 参考文章:https://mp.weixin.qq.com/s/gs2bojFLBB4IAWMyN9lfnw
*/
class JianShuWebClient : BaseWebClient() {
private val rex = "(<style data-vue-ssr-id=[\\s\\S]*?>)([\\s\\S]*]?)(<\\/style>)"
private val bodyRex = "<body class=\"([\\ss\\S]*?)\""
override fun shouldInterceptRequest(view: WebView?, url: String?): WebResourceResponse? {
val urlStr = url ?: ""
if (urlStr.startsWith(WebClientFactory.JIAN_SHU)) {
val response = Wget.get(url ?: "")
val res = darkBody(replaceCss(response, view!!.context))
val input = ByteArrayInputStream(res.toByteArray())
return WebResourceResponse("text/html", "utf-8", input)
}
return super.shouldInterceptRequest(view, url)
}
private fun darkBody(res: String): String {
val pattern = Pattern.compile(bodyRex)
val m = pattern.matcher(res)
return res
//return if (m.find()) {
// val s = "<body class=\"reader-night-mode normal-size\""
// res.replace(bodyRex.toRegex(), s)
//} else res
}
private fun replaceCss(res: String, context: Context): String {
val pattern = Pattern.compile(rex)
val m = pattern.matcher(res)
return if (m.find()) {
val css = StringUtil.getString(context.assets.open("jianshu/jianshu.css"))
val sb = StringBuilder()
sb.append(m.group(1))
sb.append(css)
sb.append(m.group(3))
val res = res.replace(rex.toRegex(), sb.toString())
res
} else {
res
}
}
}
@@ -0,0 +1,22 @@
package com.bbgo.module_content.webclient
import com.just.agentweb.WebViewClient
/**
* @author chenxz
* @date 2019/11/24
* @desc WebClientFactory
*/
object WebClientFactory {
val JIAN_SHU = "https://www.jianshu.com"
fun create(url: String): WebViewClient {
return when {
url.startsWith(JIAN_SHU) -> JianShuWebClient()
else -> BaseWebClient()
}
}
}
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator">
<scale android:fromXScale="2.0" android:toXScale="1.0"
android:fromYScale="2.0" android:toYScale="1.0"
android:pivotX="50%p" android:pivotY="50%p"
android:duration="@android:integer/config_mediumAnimTime" />
</set>
@@ -0,0 +1,10 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator"
android:zAdjustment="top">
<scale android:fromXScale="1.0" android:toXScale=".5"
android:fromYScale="1.0" android:toYScale=".5"
android:pivotX="50%p" android:pivotY="50%p"
android:duration="@android:integer/config_mediumAnimTime" />
<alpha android:fromAlpha="1.0" android:toAlpha="0"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="1000"
android:fromAlpha="0"
android:interpolator="@android:anim/decelerate_interpolator"
android:toAlpha="1.0"/>
</set>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="1500"
android:fromAlpha="1.0"
android:interpolator="@android:anim/decelerate_interpolator"
android:toAlpha="0"/>
</set>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="500"
android:fromXDelta="-30.0%p"
android:toXDelta="0.0" />
</set>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="500"
android:fromXDelta="0.0"
android:toXDelta="-30.0%p" />
</set>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="-50%p" android:toYDelta="0" android:duration="1000"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="1000" />
</set>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="0" android:toYDelta="-50%p" android:duration="1000"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="1000" />
</set>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="500"
android:fromXDelta="100.0%p"
android:toXDelta="0.0" />
</set>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="500"
android:fromXDelta="0.0"
android:toXDelta="100.0%p" />
</set>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/list_divider" />
</shape>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape>
<solid android:color="#A6000000" />
<padding android:left="8dp" android:top="4dp" android:right="8dp" android:bottom="4dp" />
<corners android:radius="2dp" />
</shape>
</item>
<item>
<shape>
<solid android:color="#99000000" />
<padding android:left="8dp" android:top="4dp" android:right="8dp" android:bottom="4dp" />
<corners android:radius="2dp" />
</shape>
</item>
</selector>
@@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="1024.0"
android:viewportWidth="1024.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#ffffff" android:pathData="M981.8,311.4c-25.7,-60.7 -62.4,-115.2 -109.2,-162.1 -46.8,-46.8 -101.3,-83.6 -162.1,-109.2 -62.2,-26.3 -128.2,-39.8 -196.2,-40.1 -0.7,0 -1.5,-0 -2.2,-0s-1.5,0 -2.2,0c-68,0.3 -134,13.8 -196.2,40.1 -60.7,25.7 -115.2,62.4 -162.1,109.2 -46.8,46.8 -83.6,101.3 -109.2,162.1 -26.6,62.9 -40.1,129.6 -40.1,198.5 0,68.8 13.5,135.6 40.1,198.5 25.7,60.7 62.4,115.2 109.2,162.1s101.3,83.6 162.1,109.2c62.2,26.3 128.2,39.8 196.2,40.1 0.7,0 1.5,0 2.2,0s1.5,-0 2.2,-0c68,-0.3 134,-13.8 196.2,-40.1 60.7,-25.7 115.2,-62.4 162.1,-109.2s83.6,-101.3 109.2,-162.1c26.6,-62.9 40.1,-129.6 40.1,-198.5C1021.8,441 1008.3,374.2 981.8,311.4zM180.4,178.3c43.1,-43.1 93.2,-76.9 149,-100.5 19.2,-8.1 38.7,-14.9 58.6,-20.3 -24.8,24.9 -47.6,57.5 -67.4,97.2 -12.7,25.4 -23.9,53.1 -33.5,82.5 -44.1,-11.8 -84.6,-27 -119.7,-45.4C171.7,187.2 176,182.7 180.4,178.3zM79.9,327.3c15.7,-37.2 36,-71.9 60.6,-103.7 39.3,21.6 85.1,39.3 135.2,52.7 -17.3,65.3 -27.1,137.8 -28.6,213L43.6,489.4C45.9,433.3 58.1,378.9 79.9,327.3zM140.5,796c-24.5,-31.8 -44.8,-66.5 -60.5,-103.7 -21.8,-51.5 -34,-106 -36.4,-162.1l203.5,0c1.5,75.2 11.3,147.6 28.6,213C225.6,756.7 179.8,774.4 140.5,796zM329.5,941.9c-55.8,-23.6 -106,-57.4 -149,-100.5 -4.4,-4.4 -8.7,-8.9 -12.9,-13.4 35.1,-18.4 75.5,-33.7 119.7,-45.5 9.6,29.4 20.8,57.1 33.5,82.5 19.9,39.7 42.6,72.3 67.4,97.2C368.2,956.8 348.6,950 329.5,941.9zM491.5,976.7c-21,-4.2 -41.6,-14.7 -61.6,-31.6 -27,-22.8 -51.5,-56 -72.7,-98.4 -11.4,-22.7 -21.5,-47.4 -30.2,-73.7 51.5,-10.8 107,-17 164.4,-18.2L491.5,976.7zM491.5,713.9c-61.3,1.2 -120.9,8.1 -176.1,19.9 -16.5,-62.1 -25.9,-131.3 -27.4,-203.4l203.5,0L491.5,713.9zM491.5,489.4l-203.5,0c1.5,-72.2 10.9,-141.3 27.4,-203.5 55.3,11.8 114.8,18.7 176.1,19.9L491.5,489.4zM491.5,264.9c-57.3,-1.2 -112.9,-7.5 -164.4,-18.2 8.7,-26.2 18.8,-50.9 30.1,-73.7 21.2,-42.4 45.7,-75.6 72.7,-98.4 19.9,-16.9 40.6,-27.4 61.6,-31.6L491.5,264.9zM694.5,77.8c55.8,23.6 106,57.4 149,100.5 4.4,4.4 8.7,8.9 12.9,13.4 -34.7,18.1 -75.4,33.6 -119.7,45.4 -9.6,-29.4 -20.8,-57 -33.5,-82.5 -19.9,-39.7 -42.6,-72.3 -67.4,-97.2C655.8,62.9 675.4,69.7 694.5,77.8zM532.5,43c21,4.2 41.6,14.7 61.5,31.6 27,22.9 51.5,56 72.7,98.4 11.4,22.7 21.4,47.4 30.1,73.6 -51.9,10.9 -107.8,17.1 -164.4,18.3L532.5,43zM532.5,305.8c61.2,-1.2 120.3,-7.9 176.1,-19.8 16.5,62.1 25.9,131.3 27.4,203.4l-203.5,0L532.5,305.8 532.5,305.8zM532.5,530.3l203.5,0c-1.5,72.1 -10.9,141.3 -27.5,203.5 -55.3,-11.8 -114.8,-18.7 -176.1,-19.9L532.5,530.3 532.5,530.3zM594,945.1c-19.9,16.9 -40.5,27.4 -61.5,31.6L532.5,754.8c57.3,1.2 112.8,7.5 164.4,18.2 -8.7,26.2 -18.8,50.9 -30.1,73.7C645.5,889.2 621,922.3 594,945.1zM843.6,841.4c-43.1,43.1 -93.2,76.9 -149,100.5 -19.2,8.1 -38.7,14.9 -58.6,20.3 24.8,-24.9 47.6,-57.5 67.4,-97.2 12.7,-25.4 23.9,-53.1 33.5,-82.5 44.1,11.7 84.6,27 119.7,45.4C852.3,832.5 848,837 843.6,841.4zM944.1,692.3c-15.7,37.2 -36,71.9 -60.6,103.7 -39.3,-21.6 -85.1,-39.3 -135.2,-52.7 17.3,-65.4 27.1,-137.8 28.6,-213l203.5,0C978.1,586.4 965.9,640.8 944.1,692.3zM776.9,489.4c-1.5,-75.2 -11.3,-147.6 -28.6,-213 50.8,-13.6 96.2,-31.3 135.2,-52.7 24.5,31.8 44.8,66.4 60.6,103.7 21.8,51.5 34,106 36.4,162.1L776.9,489.4z"/>
</vector>
@@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="1024.0"
android:viewportWidth="1024.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#ffffff" android:pathData="M768,686.1c-32.4,0 -61.4,12.8 -83.6,32.9l-304.2,-177.1c2.1,-9.8 3.8,-19.6 3.8,-29.9s-1.7,-20.1 -3.8,-29.9l300.8,-175.4c23,21.3 53.3,34.6 87,34.6 70.8,0 128,-57.2 128,-128s-57.2,-128 -128,-128c-70.8,0 -128,57.2 -128,128 0,10.2 1.7,20.1 3.8,29.9l-300.8,175.4c-23,-21.3 -53.3,-34.6 -87,-34.6 -70.8,0 -128,57.2 -128,128s57.2,128 128,128c33.7,0 64,-13.2 87,-34.6l303.8,177.5c-2.1,9 -3.4,18.3 -3.4,27.7 0,68.7 55.9,124.6 124.6,124.6s124.6,-55.9 124.6,-124.6c0,-68.7 -55.9,-124.6 -124.6,-124.6l0,0z"/>
</vector>
@@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="1024.0"
android:viewportWidth="1024.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFFFFF" android:pathData="M761.4,136.9C588.3,90.9 512,238.2 512,238.2 512,238.2 435.7,90.9 262.6,136.9 89.6,183 -5.3,414.9 208.7,623 422.7,831.1 512,910.2 512,910.2 512,910.2 601.3,831.1 815.3,623 1029.3,414.9 934.4,183 761.4,136.9"/>
</vector>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<com.bbgo.module_content.ui.WebContainer xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/cl_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/viewBackground"
android:orientation="vertical">
<include
android:id="@+id/action_bar"
layout="@layout/content_toolbar" />
</com.bbgo.module_content.ui.WebContainer>
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.appbar.AppBarLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay"
app:elevation="0dp">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:titleTextAppearance="@style/Toolbar.TitleText">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:singleLine="true"
android:textColor="@color/white"
android:textSize="@dimen/sp_18"
android:visibility="gone" />
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_share"
android:icon="@drawable/ic_action_share"
android:orderInCategory="100"
android:title="@string/action_share"
app:showAsAction="never" />
<item
android:id="@+id/action_like"
android:icon="@drawable/ic_action_white_like"
android:orderInCategory="100"
android:title="@string/action_like"
app:showAsAction="never" />
<item
android:id="@+id/action_browser"
android:icon="@drawable/ic_action_browser"
android:orderInCategory="100"
android:title="@string/action_browser"
app:showAsAction="never" />
</menu>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/colorPrimary"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="textColorPrimary" format="color" />
<attr name="viewBackground" format="color" />
</resources>
@@ -0,0 +1,85 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="avatar_width">80dp</dimen>
<dimen name="avatar_height">80dp</dimen>
<dimen name="appbar_layout_height">260dp</dimen>
<!-- item -->
<dimen name="item_tv_title">16sp</dimen>
<dimen name="item_tv_content">14sp</dimen>
<dimen name="item_tv_date">12sp</dimen>
<dimen name="item_tv_tag">12sp</dimen>
<dimen name="item_tv_author">12sp</dimen>
<dimen name="item_tv_via">12sp</dimen>
<dimen name="item_content_padding">10dp</dimen>
<dimen name="item_img_width">120dp</dimen>
<dimen name="item_img_height">90dp</dimen>
<dimen name="textSize_small_10">10sp</dimen>
<dimen name="textSize_small">12sp</dimen>
<dimen name="textSize_content">14sp</dimen>
<dimen name="textSize_titleSmall">16sp</dimen>
<dimen name="textSize_title">18sp</dimen>
<!-- dp -->
<dimen name="dp_05">0.5dp</dimen>
<dimen name="dp_1">1dp</dimen>
<dimen name="dp_2">2dp</dimen>
<dimen name="dp_3">3dp</dimen>
<dimen name="dp_4">4dp</dimen>
<dimen name="dp_5">5dp</dimen>
<dimen name="dp_6">6dp</dimen>
<dimen name="dp_8">8dp</dimen>
<dimen name="dp_10">10dp</dimen>
<dimen name="dp_12">12dp</dimen>
<dimen name="dp_16">16dp</dimen>
<dimen name="dp_18">18dp</dimen>
<dimen name="dp_20">20dp</dimen>
<dimen name="dp_24">24dp</dimen>
<dimen name="dp_26">26dp</dimen>
<dimen name="dp_28">28dp</dimen>
<dimen name="dp_30">30dp</dimen>
<dimen name="dp_36">36dp</dimen>
<dimen name="dp_46">46dp</dimen>
<dimen name="dp_50">50dp</dimen>
<dimen name="dp_54">54dp</dimen>
<dimen name="dp_60">60dp</dimen>
<dimen name="dp_80">80dp</dimen>
<dimen name="dp_90">90dp</dimen>
<dimen name="dp_100">100dp</dimen>
<dimen name="dp_110">110dp</dimen>
<dimen name="dp_168">168dp</dimen>
<dimen name="dp_180">180dp</dimen>
<dimen name="dp_200">200dp</dimen>
<dimen name="dp_230">230dp</dimen>
<dimen name="dp_240">240dp</dimen>
<dimen name="dp_260">260dp</dimen>
<dimen name="dp_280">280dp</dimen>
<dimen name="dp_300">300dp</dimen>
<!-- sp -->
<dimen name="sp_8">8sp</dimen>
<dimen name="sp_9">9sp</dimen>
<dimen name="sp_10">10sp</dimen>
<dimen name="sp_12">12sp</dimen>
<dimen name="sp_13">13sp</dimen>
<dimen name="sp_14">14sp</dimen>
<dimen name="sp_15">15sp</dimen>
<dimen name="sp_16">16sp</dimen>
<dimen name="sp_17">17sp</dimen>
<dimen name="sp_18">18sp</dimen>
<dimen name="sp_20">20sp</dimen>
<dimen name="sp_22">22sp</dimen>
<dimen name="sp_24">24sp</dimen>
<dimen name="sp_40">40sp</dimen>
<dimen name="sp_50">50sp</dimen>
<!--BottomNavigationView 的选中没有选中的字体大小-->
<dimen name="design_bottom_navigation_active_text_size">@dimen/sp_13</dimen>
<dimen name="design_bottom_navigation_text_size">@dimen/sp_12</dimen>
</resources>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="expandable_text"/>
<item type="id" name="expand_collapse"/>
<item name="statusbarutil_fake_status_bar_view" type="id" />
<item name="statusbarutil_translucent_view" type="id" />
</resources>
@@ -0,0 +1,11 @@
<resources>
<string name="app_name">WebContent模块</string>
<string name="share_article_url">%1$s分享【%2$s】:%3$s</string>
<string name="action_share">分享</string>
<string name="login_tint">请先登录</string>
<string name="action_like">收藏</string>
<string name="action_un_like">取消收藏</string>
<string name="action_browser">用浏览器打开</string>
<string name="collect_success">收藏成功</string>
<string name="cancel_collect_success">已取消收藏</string>
</resources>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="transition_movie_img">transition_movie_img</string>
<string name="transition_news_img">transition_news_img</string>
<string name="transition_book_img">transition_book_img</string>
</resources>
@@ -0,0 +1,17 @@
package com.bbgo.module_content
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}