Commit dae1df1c by fengchen

lib_Autonomous 是当前开发项目独有的lib 用来放资源文件 自定义view 一些只有这个项目用到的一些公用的方法

lib_base 用来存放 一些图片选择 号码选择 扫一扫 这种通用的Activity
lic_common 用来存放公用的工具
lib_common_view 用来存放公共的view 以及 一些Activity 这类的
lib_net 网络框架

第三方现在都放在lib_common 里   还有一些没放,根据需要自己添加

集成关系 是 lib_common -> lib_commonview ->lib_net ->
 lib_base - >lib_Autonomous
parents

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'WMRouter'
apply plugin: 'android-aspectjx'
String package_name = "com.yumeng.hibro"
android {
compileSdkVersion compile_sdk_version
defaultConfig {
applicationId package_name
multiDexEnabled true
minSdkVersion min_sdk_version
targetSdkVersion target_sdk_version
versionCode version_code
versionName version_name
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
flavorDimensions "versionCode"
productFlavors {
dev {
applicationIdSuffix ".dev"
manifestPlaceholders.put("PACKAGE_NAME", "${package_name}.dev")
}
alpha {
applicationIdSuffix ".alpha"
manifestPlaceholders.put("PACKAGE_NAME", "${package_name}.alpha")
}
ga {
manifestPlaceholders.put("PACKAGE_NAME", "${package_name}")
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
androidExtensions {
experimental = true
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
implementation "com.sankuai.waimai.router:router:${wmrouter_version}"
kapt "com.sankuai.waimai.router:compiler:${wmrouter_version}"
implementation val.lib_Autonomous
if (!isModule.toBoolean()) {
// implementation val.module_home
// implementation val.module_mine
// implementation val.module_news
}
}
# 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
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yumeng.hibro">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".TestSecondActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
/>
<activity android:name=".TestthreeActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
/>
</application>
</manifest>
\ No newline at end of file
package com.yumeng.hibro
import android.Manifest
import android.content.Intent
import android.os.Bundle
import androidx.lifecycle.Observer
import com.yumeng.hibro.model.TestEventModelp
import com.yumeng.hibro.model.TestEventModels
import com.yumeng.hibro.viewModel.MainViewModel
import com.yumeng.libbase.activity.EditContentActivity
import com.yumeng.libbase.activity.matisse.matisse.GlideEngine
import com.yumeng.libbase.activity.matisse.matisse.Matisse
import com.yumeng.libbase.activity.matisse.matisse.MimeType
import com.yumeng.libbase.activity.telphone.TelephoneCodeActivity
import com.yumeng.libbase.helper.DialogHelper
import com.yumeng.libbaseProject.activity.BaseImVMActivity
import com.yumeng.libbaseProject.eventBus.MessageChatEvent
import com.yumeng.libcommon.event.MessageEvent
import com.yumeng.libcommon.ext.doAsync
import com.yumeng.libcommon.ext.putData
import com.yumeng.libcommon.ext.startKtxActivity
import com.yumeng.libcommon.ext.startKtxActivityForResult
import com.yumeng.libcommon.helper.Preference
import com.yumeng.libcommon.rxManager.RxPermissions
import com.yumeng.libcommon.utils.LogUtils
import com.yumeng.tillo.QRCodeScanActivity
import kotlinx.android.synthetic.main.activity_main.*
import org.greenrobot.eventbus.EventBus
class MainActivity : BaseImVMActivity<MainViewModel>() {
companion object {
private const val REQUEST_CODE_CHOOSE = 23
private const val BASE_REQUEST_CODE = 24
}
override fun providerVMClass(): Class<MainViewModel>? = MainViewModel::class.java
override fun getLayoutResId() = R.layout.activity_main
override fun initData() {
mViewModel.getTest()
}
override fun initView() {
getNet.setOnClickListener {
mViewModel.getTest()
}
scan.setOnClickListener {
RxPermissions(this).request(Manifest.permission.CAMERA)
.subscribe { aBoolean ->
if (aBoolean) {
QRCodeScanActivity.start(this, true)
}
}
}
pick.setOnClickListener {
RxPermissions(this).request(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
?.subscribe { aBoolean ->
//权限已经开启 enableCrop:是否裁剪
if (aBoolean == true) {
Matisse.from(this)
.choose(MimeType.ofAll(), false)
.countable(false)
.maxOriginalSize(10 * 1024 * 1024)//最大设置10M每张
.originalEnable(true)
.theme(R.style.Matisse_Zhihu)
.maxSelectable(9)
.imageEngine(GlideEngine())
.forResult(REQUEST_CODE_CHOOSE)
}
}
}
pickDialog.setOnClickListener {
DialogHelper.showPhotoDialog(this, object : DialogHelper.OnPhotoCallback {
override fun onSuccess(path: String) {
LogUtils.d("test", "path:$path")
}
override fun onFailure() {
}
})
}
phonePick.setOnClickListener {
startKtxActivityForResult<TelephoneCodeActivity>(BASE_REQUEST_CODE)
}
editContent.setOnClickListener {
startKtxActivityForResult<EditContentActivity>(extra = Bundle().apply {
putString(EditContentActivity.TITLE_KEY, "ceshi")
putString(EditContentActivity.RESULT_KEY, "ceshi1")
}, requestCode = BASE_REQUEST_CODE)
}
saveShareData.setOnClickListener {
//第一种方式
Preference<String>().putValue(Preference.USER_JSON, "555555")
//第二种方式
var userId by Preference(Preference.USER_ID, "")
userId = "22"
//第三种方式
Preference("").putValue(Preference.TOKEN, "12344444")
//第四种
1123123.putData("tttt")
}
getShareData.setOnClickListener {
val userInfo by Preference(Preference.USER_JSON, "")
val userId by Preference(Preference.USER_ID, "")
val token by Preference(Preference.TOKEN, "")
val tttt by Preference("tttt", 0)
val tttt2 = Preference<Long>().getValue("tttt", 0)
LogUtils.e("test", "userInfo :$userInfo")
LogUtils.e("test", "userId :$userId")
LogUtils.e("test", "token :$token")
LogUtils.e("test", "tttt :$tttt")
LogUtils.e("test", "tttt2 :$tttt2")
}
sendEvent.setOnClickListener {
EventBus.getDefault().post(MessageChatEvent("111111","22222").apply {
putValue("a","aaaaa")
putValue("b","bbbbb")
putValue("c",TestEventModels("lili","25"))
// putValue("d", TestEventModelp("bibi","26"))
})
}
jumpSecond.setOnClickListener {
startKtxActivity<TestSecondActivity>()
}
jumpThree.setOnClickListener {
startKtxActivity<TestthreeActivity>()
}
}
override fun startObserve() {
super.startObserve()
mViewModel.uiState.observe(this, Observer {
it.showError?.let { error ->
LogUtils.e("test", "showError :$error")
}
it.showLoading?.let { loading ->
LogUtils.e("test", "showError :$loading")
}
it.showSuccess?.let { success ->
LogUtils.e("test", "showError :$success")
}
})
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
}
override fun onMessageEvent(event: MessageEvent) {
super.onMessageEvent(event)
val message = event as MessageChatEvent
val content = "msg:${message.target} ${message.behavior} ${message.getData(
"a",
""
)} ${message.getData("b", "")}"
val content2 = "name:${message.getData("c",TestEventModels()).name} age: ${message.getData("c",TestEventModels()).age}"
// val content3 = "name:${message.getData("d",TestEventModelp()).nameP} age: ${message.getData("d",TestEventModelp()).ageP}"
LogUtils.e("test", "showEvent :$content $content2 ")//$content3
}
}
\ No newline at end of file
package com.yumeng.hibro
import android.app.Activity
import android.os.Bundle
import android.os.PersistableBundle
import com.yumeng.hibro.viewModel.MainViewModel
import com.yumeng.libbaseProject.activity.BaseImVMActivity
import com.yumeng.libcommon.event.MessageEvent
import com.yumeng.libcommon.manage.ActivityManage
import com.yumeng.libcommon.utils.LogUtils
import com.yumeng.libcommonview.activity.CommonToolbarActivity
import kotlinx.android.synthetic.main.activity_second.*
class TestSecondActivity : CommonToolbarActivity(){
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
setContentView(R.layout.activity_second)
}
override fun initView() {
super.initView()
twoCheck.setOnClickListener {
val main =ActivityManage.existActivity(MainActivity::class.java)
val two = ActivityManage.existActivity(TestSecondActivity::class.java)
val three = ActivityManage.existActivity(TestthreeActivity::class.java)
LogUtils.e("test","main:$main two$two three$three")
ActivityManage.recreateAllActivity()
}
}
}
\ No newline at end of file
package com.yumeng.hibro
import android.os.Bundle
import android.os.PersistableBundle
import com.yumeng.hibro.viewModel.MainViewModel
import com.yumeng.libbaseProject.activity.BaseImVMActivity
import com.yumeng.libcommon.event.MessageEvent
import com.yumeng.libcommon.manage.ActivityManage
import com.yumeng.libcommon.utils.LogUtils
import com.yumeng.libcommonview.activity.CommonToolbarActivity
import kotlinx.android.synthetic.main.activity_three.*
class TestthreeActivity : CommonToolbarActivity() {
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
setContentView(R.layout.activity_three)
}
override fun initView() {
super.initView()
threeCheck.setOnClickListener {
val main =ActivityManage.existActivity(MainActivity::class.java)
val two = ActivityManage.existActivity(TestSecondActivity::class.java)
val three = ActivityManage.existActivity(TestthreeActivity::class.java)
LogUtils.e("test","main:$main two$two three$three")
ActivityManage.finishAllActivity()
}
}
}
\ No newline at end of file
package com.yumeng.hibro.model
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
import java.io.Serializable
@Parcelize
data class TestEventModelp(
var nameP: String? = null,
var ageP: String? = null
) : Parcelable
\ No newline at end of file
package com.yumeng.hibro.model
import java.io.Serializable
data class TestEventModels(
var name: String? = null,
var age: String? = null
) : Serializable
\ No newline at end of file
package com.yumeng.hibro.viewModel
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.yumeng.libbaseProject.service.ResponseModel.TestResponse
import com.yumeng.libbaseProject.service.repository.NewsDetailRepository
import com.yumeng.libcommon.utils.LogUtils
import com.yumeng.libcommonview.viewmodel.BaseViewModel
import com.yumeng.libcore.IResult
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class MainViewModel :BaseViewModel(){
data class MainUiModel(
val showLoading: Boolean,
val showError: String?,
val showSuccess:List<TestResponse>?
)
private val _uiState = MutableLiveData<MainUiModel>()
val uiState: LiveData<MainUiModel>
get() = _uiState
private fun emitUiState(
showLoading: Boolean = false,
showError: String? = null,
showSuccess:List<TestResponse>?=null
) {
val uiModel =
MainUiModel(showLoading, showError, showSuccess)
_uiState.value = uiModel
}
private val repository by lazy { NewsDetailRepository() }
fun getTest() {
viewModelScope.launch {
withContext(Dispatchers.Main) {
emitUiState(showLoading = true)
}
val result = repository.getArticles("0")
withContext(Dispatchers.Main) {
if (result is IResult.Success) {
val data = result.data
if (data?.records?.size == 0) {
emitUiState(showError = "123123")
return@withContext
}
emitUiState(
showSuccess = data?.records
)
} else if (result is IResult.Error) {
LogUtils.e("test","result:${result.toString()}")
emitUiState(showError = result.exception.message)
}
}
}
}
}
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#008577"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/scan"
android:text="扫一扫"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/pick"
android:text="图片选取"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/pickDialog"
android:text="图片对话框"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/phonePick"
android:text="号码选择"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/editContent"
android:text="内容编辑"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/saveShareData"
android:text="share存"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/getShareData"
android:text="Share取"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/getNet"
android:text="网络请求"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/sendEvent"
android:text="EventBus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/jumpSecond"
android:text="跳转Second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/jumpThree"
android:text="跳转Three"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/twoCheck"
android:text="Second"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/threeCheck"
android:text="Three"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
</resources>
<resources>
<string name="app_name">ProjectFrame</string>
</resources>
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.3.61'
ext.wmrouter_version = '1.2.0'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.sankuai.waimai.router:plugin:$wmrouter_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4'
}
}
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
ext {
//SDK
min_sdk_version = 21
target_sdk_version = 28
compile_sdk_version = 28
//版本
version_code = 1
version_name = "1.0.0"
//cloud 专用
junit_version = '4.12'
test_runner_version = '1.2.0-alpha03'
test_espresso_core_version = '3.2.0-alpha03'
retrofit_version = '2.4.0'
rx_java_version = '2.2.8'
rx_android_version = '2.1.1'
minify_enabled = true
zip_align_enabled = true
shrinking_enabled = true
val = [
lib_common : project(':lib_common'),//通用lib
lib_common_view : project(':lib_common_view'),//界面 和 一些view
lib_net : project(':lib_net'),//网络请求
lib_base : project(':lib_base'),//一些通用的Activity
lib_Autonomous : project(':lib_Autonomous'),//项目独有
lib_emoji : project(':lib_emoji'),
lib_websocket : project(':lib_websocket'),
kotlin_stdlib :"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version",//
androidxCoreKtx :'androidx.core:core-ktx:1.1.0',//
constraintlayout : "androidx.constraintlayout:constraintlayout:1.1.3",//
appcompat :'androidx.appcompat:appcompat:1.1.0',//
material : 'com.google.android.material:material:1.2.0-alpha02',//解决编译错误
circleimageview : 'de.hdodenhof:circleimageview:3.0.1',//圆形头像
smartRefreshLayoutCore : 'com.scwang.smart:refresh-layout-kernel:2.0.0-alpha-1', //核心必须依赖
smartRefreshLayoutHeader : 'com.scwang.smart:refresh-header-classics:2.0.0-alpha-1',//
XTabLayout : 'com.androidkun:XTabLayout:1.1.4',//Tab的效果
GSYVideoPlayer :'com.shuyu:GSYVideoPlayer:7.1.1',//视频播放器
materialishProgress :'com.pnikosis:materialish-progress:1.7',//加载Progress
glide : 'com.github.bumptech.glide:glide:4.10.0',//
glideCompiler :"com.github.bumptech.glide:compiler:4.10.0",//
glideAnnotations :"com.github.bumptech.glide:annotations:4.10.0",//
glideOkhttp3 :'com.github.bumptech.glide:okhttp3-integration:4.10.0',//
picasso :"com.squareup.picasso:picasso:2.71828",//图片加载
eventbus : 'org.greenrobot:eventbus:3.1.1',//eventBus
richtext : 'com.zzhoujay.richtext:richtext:3.0.8',//富文本
dialogsCore :'com.afollestad.material-dialogs:core:3.1.1',//Dialog
dialogsInput :'com.afollestad.material-dialogs:input:3.1.1',//Dialog
immersionbar :'com.gyf.immersionbar:immersionbar:3.0.0',//沉浸式状态导航栏
immersionbarComponents :'com.gyf.immersionbar:immersionbar-components:3.0.0',//
immersionbarKtx :'com.gyf.immersionbar:immersionbar-ktx:3.0.0',//
skeleton :'com.ethanhua:skeleton:1.1.2',//骨架加载预览
shimmerlayout : 'io.supercharge:shimmerlayout:2.1.0',//骨架加载预览
ExpandableTextView :'com.github.MZCretin:ExpandableTextView:v1.6.1',//展开可回收TextView
ucrop :'com.github.yalantis:ucrop:2.2.2',//图像裁剪
ktxCoroutinesCore :'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2',//
loggingInterceptor :'com.squareup.okhttp3:logging-interceptor:3.10.0',//
retrofit :'com.squareup.retrofit2:retrofit:2.6.2',//
retrofitGson :'com.squareup.retrofit2:converter-gson:2.6.2',//
rxjava :"io.reactivex.rxjava2:rxjava:${rx_java_version}",//
rxjavaRxandroid :"io.reactivex.rxjava2:rxandroid:${rx_android_version}",//
retrofitConverters :"com.squareup.retrofit2:retrofit-converters:$retrofit_version",//
retrofitAdapter : "com.squareup.retrofit2:adapter-rxjava2:$retrofit_version",//
PersistentCookieJar : 'com.github.franmontiel:PersistentCookieJar:v1.0.1',//持久化cookie的方式
BaseRecyclerViewAdapterHelper:'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.47',//一个Adapter
fastjson :'com.alibaba:fastjson:1.2.59',//fastjson
litepalKtx :'org.litepal.android:kotlin:3.0.0',//litepal// 支持kotlin语言
// litepal :"org.litepal.android:core:2.0.0",//
PermissionsKt :'com.github.sembozdemir:PermissionsKt:1.0.0',//运行时权限,可能跟rxjava 重复
lifecycleViewMode :"androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-rc02",//生命周期监听 viewMode
lifecycleExtensions : 'androidx.lifecycle:lifecycle-extensions:2.2.0-rc02',//生命周期监听
recyclerview : 'androidx.recyclerview:recyclerview:1.1.0-rc01',//
jpinyin : "com.github.SilenceDut:jpinyin:v1.0",//汉字转拼音的Java开源类库
PickerView :"com.contrarywind:Android-PickerView:4.1.7",//纵向选择view
wheelview :"com.contrarywind:wheelview:4.0.9",// 纵向选择view
skinSupport :'skin.support:skin-support:4.0.4',//换肤
skinAppCompat :'skin.support:skin-support-appcompat:4.0.4',//换肤
skinDesign :'skin.support:skin-support-design:4.0.4',//换肤
skinCardView :'skin.support:skin-support-cardview:4.0.4',//换肤
skinConstraintLayout : 'skin.support:skin-support-constraint-layout:4.0.4',//
imagezoom :"it.sephiroth.android.library.imagezoom:library:1.0.4",//ImageViewTouch 只支持图片放大和缩小位置不会变动
Zxing :"cn.bingoogolapple:bga-qrcode-zxing:1.3.6",// zxing 二维码
googleMapService :'com.google.android.gms:play-services-maps:17.0.0',//谷歌地图map
googleMapLocation :'com.google.android.gms:play-services-location:17.0.0',//谷歌地图定位
places : 'com.google.android.libraries.places:places:1.1.0',//谷歌地图place
stream :'com.annimon:stream:1.1.8',//数据列表的一些操作 for 过滤啊 mapto啊
badgeview :'cn.bingoogolapple:bga-badgeview-api:1.1.8',//
badgeviewCompiler :"cn.bingoogolapple:bga-badgeview-compiler:1.1.8",//
signalProtocol :'org.whispersystems:signal-protocol-android:2.7.0',//会话加密 应该是用于端对端加密
workRuntime :"androidx.work:work-runtime-ktx:2.0.0",//可以让异步循环变得很容易,即使app退出或者重新启动,这些任务仍会运行
androidXmultidex : 'androidx.multidex:multidex:2.0.1',//
webrtc : "org.webrtc:google-webrtc:1.0.30039",//webRtc
DragPhotoView : "com.github.githubwing:DragPhotoView:1.0.1",//高仿微信可拖拽返回的PhotoView 这个应该没用了
dragclosehelper : 'com.github.bauer-bao:dragclosehelper:0.0.9',//图片可拖拽
subsampling : 'com.davemorrissey.labs:subsampling-scale-image-view:3.10.0',//加载长图
WebSocket : 'org.java-websocket:Java-WebSocket:1.4.1'//webSoceket
// lib_cloud_storage: project(':lib_cloud_storage'),
// module_news: project(':module_news'),
]
}
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
kotlin.code.style=official
isModule=false
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
String devUrl = "192.168.1.236:22002/"// 测试url
String alphaUrl = "test.tlifang.com/news/app"// 发布测试使用
String gaUrl = "192.168.1.95:22002"// 正式环境
android {
compileSdkVersion compile_sdk_version
// sourceSets.main {
// jniLibs.srcDir 'libs'
// jni.srcDirs = [] //disable automatic ndk-build call
// res.srcDirs = ['src/main/res', 'src/main/res-blue']
// }
defaultConfig {
minSdkVersion min_sdk_version
targetSdkVersion target_sdk_version
versionCode version_code
versionName version_name
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
packagingOptions {
exclude 'META-INF/rxjava.properties'
}
flavorDimensions "versionCode"
productFlavors {
dev {
buildConfigField "String", "BASE_URL", "\"http://$devUrl/\""//
}
alpha {
buildConfigField "String", "BASE_URL", "\"https://$alphaUrl/\""
}
ga {
buildConfigField "String", "BASE_URL", "\"http://$gaUrl/\""
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation "com.sankuai.waimai.router:router:${wmrouter_version}"
kapt "com.sankuai.waimai.router:compiler:${wmrouter_version}"
api val.lib_base
}
# 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
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.yumeng.libbaseProject">
<application
android:name=".application.MyApplication"
>
</application>
</manifest>
package com.yumeng.libbaseProject.activity
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.yumeng.libbase.helper.DialogHelper
import com.yumeng.libbaseProject.Contants.Constants
import com.yumeng.libbaseProject.R
import com.yumeng.libbaseProject.eventBus.MessageChatEvent
import com.yumeng.libcommon.helper.Preference
import com.yumeng.libcommon.utils.OSUtils
import com.yumeng.libcommonview.activity.CommonToolbarActivity
import com.yumeng.libcommonview.base.BaseVMActivity
import com.yumeng.libcommonview.viewmodel.BaseViewModel
import org.greenrobot.eventbus.EventBus
//
abstract class BaseImVMActivity<VM : BaseViewModel> : BaseVMActivity<VM>() {
private var alertDialog: AlertDialog? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
OSUtils.isFloatPermission(this)
}
override fun onPause() {
super.onPause()
if (alertDialog != null && alertDialog!!.isShowing) {
alertDialog!!.dismiss()
}
}
override fun onStart() {
super.onStart()
//TODO
// AccountHelper.reconnection()
// CommonInterface.checkInitiating(this, AppSharePre.getPersonalInfo(), false, null)
}
override fun onResume() {
super.onResume()
var isFloating by Preference(Constants.HOME_FLOAT_PERMISSION,false)
if (isFloating) {
isFloating = false
if (OSUtils.isFloatPermission(this)) {
EventBus.getDefault().post(MessageChatEvent(Constants.TARGET_VIDEO_ACTIVITY, Constants.MESSAGE_EVENT_START_FLOATING_WINDOW))
} else {
showPermissionDialog()
}
}
}
private fun showPermissionDialog() {
//TODO
// alertDialog = DialogHelper.showSimpleDialog(this, getString(R.string.you_cant_minimize_a_video_call_as_authorized), getString(R.string.enable), DialogInterface.OnClickListener{ dialog, which -> startActivityForResult(
// Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:$packageName")), Constants.HOME_FLOAT_PERMISSION_CODE) })
// alertDialog?.show()
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
val isHome = intent.getBooleanExtra(Constants.HOME_FLOAT_PERMISSION, false)
if (isHome) {
showPermissionDialog()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == Constants.HOME_FLOAT_PERMISSION_CODE) {
if (OSUtils.isFloatPermission(this)) {
EventBus.getDefault().post(MessageChatEvent(Constants.TARGET_VIDEO_ACTIVITY, Constants.MESSAGE_EVENT_START_FLOATING_WINDOW))
}
}
}
override fun onDestroy() {
mViewModel.let {
lifecycle.removeObserver(it)
}
super.onDestroy()
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.application
import android.content.Context
import android.provider.Settings
import android.util.Log
import com.danikula.videocache.HttpProxyCacheServer
import com.vanniktech.emoji.EmojiManager
import com.vanniktech.emoji.ios.IosEmojiProvider
import com.yumeng.libbaseProject.model.UserInfo
import com.yumeng.libbaseProject.router.RouterManger
import com.yumeng.libcommon.helper.Preference
import com.yumeng.libcommon.utils.LogUtils
import com.yumeng.libcommon.utils.MyActivityLifeCycleCallbacks
import com.yumeng.libcommonview.theme.Theme
import org.litepal.LitePal.use
import org.litepal.LitePalDB
import skin.support.SkinCompatManager
import skin.support.app.SkinAppCompatViewInflater
import skin.support.app.SkinCardViewInflater
import skin.support.constraint.app.SkinConstraintViewInflater
import skin.support.design.app.SkinMaterialViewInflater
import kotlin.properties.Delegates
open class MyApplication : BaseApplication() {
companion object {
var CONTEXT: Context by Delegates.notNull()
var CURRENT_USER: UserInfo? = null
var instance: MyApplication? = null
fun isForeground(): Boolean {
return MyActivityLifeCycleCallbacks.isApplicationInForeground()
}
fun isLogin(context: Context, toDo: () -> Unit) {
val userInfo by Preference(
Preference.USER_JSON,
""
)
Log.e("UserInfo", "${userInfo.toString()}")
if (!userInfo.isNullOrEmpty()) {
toDo()
} else {
RouterManger.startLoginActivity(context)
}
}
fun isLogin(): Boolean {
val userInfo by Preference(
Preference.USER_JSON,
""
)
return !userInfo.isNullOrEmpty()
}
}
override fun onCreate() {
super.onCreate()
instance = this
CONTEXT = this
initSkin()
registerNetWorkChangedReceiver()
// if (CURRENT_USER != null && !existMainActivity())
// initDataBase(CURRENT_USER?.getId())
// notifier = EaseNotifier(this)
setMessageChannel(0)
setMuteChannel()
listenForScreenTurningOff()
EmojiManager.install(IosEmojiProvider())
}
//初始化数据库
fun initDataBase(dbName: String?) {
val litePalDB = LitePalDB.fromDefault(dbName)
use(litePalDB)
}
//手机开屏
private fun listenForScreenTurningOff() {
// val screenStateFilter = IntentFilter(Intent.ACTION_SCREEN_ON)
// registerReceiver(object : BroadcastReceiver() {
// override fun onReceive(context: Context, intent: Intent) {
// if (intent.action != null && intent.action == Intent.ACTION_SCREEN_ON) {
// val activity: Activity = MyApplication.getCurrentActivity()
// if (activity !is LoginActivity) {
// notifyForeground()
// }
// }
// }
// }, screenStateFilter)
}
private fun initSkin() {
Theme.Companion.init(this)
SkinCompatManager.withoutActivity(this)
.addInflater(SkinAppCompatViewInflater()) // 基础控件换肤
.addInflater(SkinMaterialViewInflater()) // material design
.addInflater(SkinConstraintViewInflater()) // ConstraintLayout
.addInflater(SkinCardViewInflater()) // CardView v7
.setSkinStatusBarColorEnable(true) // 关闭状态栏换肤
// .setSkinWindowBackgroundEnable(false) // 关闭windowBackground换肤
// .setSkinAllActivityEnable(false) // true: 默认所有的Activity都换肤; false: 只有实现SkinCompatSupportable接口的Activity换肤
.loadSkin()
}
//注册网络监听广播
fun registerNetWorkChangedReceiver() {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //实例化IntentFilter对象
// val filter = IntentFilter()
// filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
// mPushReceiver = MPushReceiver()
// //注册广播接收
// registerReceiver(mPushReceiver, filter)
// }
}
private fun notifyForeground() { // 前台
// AccountHelper.INSTANCE.reconnection()
}
fun bindUser() {
// if (!TextUtils.isEmpty(CURRENT_USER?.getId())) {
// MPush.I.bindAccount(CURRENT_USER?.getId(), "mpush:" + (Math.random() * 10).toInt())
// }
}
fun startPush() {
// userInfo = AppSharePre.getPersonalInfo()
// if (userInfo != null) {
// initPush(CURRENT_USER?.getId())
// MPush.I.checkInit(this).startPush()
// bindUser()
// }
}
/**
* mPush相关
*/
fun initPush(userId: String?) { //公钥有服务端提供和私钥对应
// val cc: ClientConfig = ClientConfig.build()
// .setPublicKey(Constants.PUSH_PUBLIC_KEY)
// .setAllotServer(Constants.MpushUrl)
// .setDeviceId(getDeviceId())
// .setClientVersion(BuildConfig.VERSION_NAME)
// .setEnableHttpProxy(true)
// .setUserId(userId)
// MPush.I.checkInit(applicationContext).setClientConfig(cc)
}
private fun getDeviceId(): String? {
val ANDROID_ID = Settings.System.getString(
contentResolver,
Settings.Secure.ANDROID_ID
)
LogUtils.e("TAG_deviceId", ANDROID_ID)
return ANDROID_ID
}
//设置消息渠道 type:0为普通消息渠道 1为rtc渠道
fun setMessageChannel(type: Int) {
// val notificationManager =
// MyApplication.context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// if (Build.VERSION.SDK_INT >= 26) { // Create the notification channel for Android 8.0
// @SuppressLint("WrongConstant") val channel = NotificationChannel(
// if (type == 0) Constants.CHANNEL_ID else Constants.VIDEO_CHANNEL,
// if (type == 0) getString(R.string.message_channel) else getString(R.string.video_channel),
// NotificationManager.IMPORTANCE_HIGH
// )
// channel.vibrationPattern = Constants.VIBRATION_PATTERN
// channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
// if (type == 1) {
// channel.setSound(
// Uri.parse("android.resource://" + this.packageName.toString() + "/" + R.raw.ic_incoming_telegram),
// Notification.AUDIO_ATTRIBUTES_DEFAULT
// )
// }
// notificationManager.createNotificationChannel(channel)
// }
}
//设置静音渠道
fun setMuteChannel() {
// val notificationManager =
// MyApplication.context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// if (Build.VERSION.SDK_INT >= 26) { // Create the notification channel for Android 8.0
// @SuppressLint("WrongConstant") val channel = NotificationChannel(
// Constants.MUTE_CHANNEL_ID
// , getString(R.string.silent_channel), NotificationManager.IMPORTANCE_LOW
// )
// channel.vibrationPattern = Constants.VIBRATION_PATTERN
// channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
// channel.setSound(null, null)
// notificationManager.createNotificationChannel(channel)
// }
}
private var proxy: HttpProxyCacheServer? = null
fun getProxy(context: Context): HttpProxyCacheServer? {
val app = context.applicationContext as MyApplication
return if (app.proxy == null) app.newProxy().also { app.proxy = it } else app.proxy
}
private fun newProxy(): HttpProxyCacheServer {
return HttpProxyCacheServer(this)
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.eventBus
import com.yumeng.libcommon.event.MessageEvent
//如果需要 自定义一些自己的参数 可以这么写
//但是 在 onMessageEvent 一定要把 MessageEvent 转成 自定义的Model
// val message = event as MessageChatEvent
class MessageChatEvent : MessageEvent {
var target: String? = null//接收对象
var behavior: String? = null//行为
var includeMe: Boolean? = false
var leaveUser: Long? = 0
var groupName: String? = null
var roomId: String? = null
var num: Int? = 0//离线消息数
constructor(target: String?, behavior: String?) {
this.target = target
this.behavior = behavior
}
constructor(target: String?, behavior: String?, includeMe: Boolean?) {
this.target = target
this.behavior = behavior
this.includeMe = includeMe
}
constructor(target: String?, behavior: String?, leaveUser: Long?) {
this.target = target
this.behavior = behavior
this.leaveUser = leaveUser
}
constructor(target: String?, behavior: String?, groupName: String?, roomId: String?) {
this.target = target
this.behavior = behavior
this.groupName = groupName
this.roomId = roomId
}
constructor(target: String?, behavior: String?, num: Int?, roomId: String?) {
this.target = target
this.behavior = behavior
this.roomId = roomId
this.num = num
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.ext
import com.yumeng.libbaseProject.utils.DataUtils
fun Long.toMessageDate():String{
return DataUtils.formatTimeBase(this)
}
\ No newline at end of file
package com.yumeng.libbaseProject.helper.measure
import android.view.View
import com.yumeng.libcommon.context.AppContextWrapper
import com.yumeng.libcommon.helper.DensityHelper
import com.yumeng.libcommon.utils.ScreenUtils
object MeasureHelper {
fun calculatePopWindowPos(anchorView: View?, contentView: View?): IntArray {
val windowPos = IntArray(2)
val anchorLoc = IntArray(2)
// 获取锚点View在屏幕上的左上角坐标位置
anchorView?.getLocationOnScreen(anchorLoc)
val screenWidth = ScreenUtils.getScreenWidthPoint(contentView?.context)
contentView?.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
// 计算contentView的高宽
val windowHeight = contentView?.measuredHeight
val windowWidth = contentView?.measuredWidth
// 判断需要向上弹出还是向下弹出显示
windowPos[0] = screenWidth - windowWidth!!
windowPos[1] = anchorLoc[1] - windowHeight!!
return windowPos
}
fun calculatePopWindowPos2(anchorView: View?, contentView: View?): IntArray {
val windowPos = IntArray(2)
val anchorLoc = IntArray(2)
// 获取锚点View在屏幕上的左上角坐标位置
anchorView?.getLocationOnScreen(anchorLoc)
val anchorHeight = anchorView?.height?:0
// 获取屏幕的高宽
val screenHeight = ScreenUtils.getScreenHeightPoint(contentView?.context)
val screenWidth = ScreenUtils.getScreenWidthPoint(contentView?.context)
contentView?.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
// 计算contentView的高宽
val windowHeight = contentView?.measuredHeight
val windowWidth = contentView?.measuredWidth
// 判断需要向上弹出还是向下弹出显示
val isNeedShowUp = screenHeight - anchorLoc[1] - anchorHeight < windowHeight ?: 0
if (isNeedShowUp) {
windowPos[0] = screenWidth - windowWidth!!
windowPos[1] = anchorLoc[1] - windowHeight!!
} else {
windowPos[0] = screenWidth - windowWidth!!
windowPos[1] = anchorLoc[1] + anchorHeight
}
return windowPos
}
fun getImageLayoutParams(width: Int, height: Int): MeasureModel {
val mContext = AppContextWrapper.getApplicationContext()
var measuredWidth = width.toDouble()
var measuredHeight = height.toDouble()
val minWidth =
DensityHelper.dp2px(mContext, 80f)
val maxWidth =
DensityHelper.dp2px(mContext, 180f)
val minHeight =
DensityHelper.dp2px(mContext, 80f)
val maxHeight =
DensityHelper.dp2px(mContext, 180f)
val widthInBounds = measuredWidth >= minWidth && measuredWidth <= maxWidth
val heightInBounds = measuredHeight >= minHeight && measuredHeight <= maxHeight
if (!widthInBounds || !heightInBounds) {
val minWidthRatio = measuredWidth / minWidth
val maxWidthRatio = measuredWidth / maxWidth
val minHeightRatio = measuredHeight / minHeight
val maxHeightRatio = measuredHeight / maxHeight
if (maxWidthRatio > 1 || maxHeightRatio > 1) {
if (maxWidthRatio >= maxHeightRatio) {
measuredWidth /= maxWidthRatio
measuredHeight /= maxWidthRatio
} else {
measuredWidth /= maxHeightRatio
measuredHeight /= maxHeightRatio
}
measuredWidth = Math.max(measuredWidth, minWidth.toDouble())
measuredHeight = Math.max(measuredHeight, minHeight.toDouble())
} else if (minWidthRatio < 1 || minHeightRatio < 1) {
if (minWidthRatio <= minHeightRatio) {
measuredWidth /= minWidthRatio
measuredHeight /= minWidthRatio
} else {
measuredWidth /= minHeightRatio
measuredHeight /= minHeightRatio
}
measuredWidth = Math.min(measuredWidth, maxWidth.toDouble())
measuredHeight = Math.min(measuredHeight, maxHeight.toDouble())
}
}
val measureModel = MeasureModel()
measureModel.width = measuredWidth.toInt()
measureModel.height = measuredHeight.toInt()
return measureModel
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.helper.measure;
import com.google.gson.annotations.Expose;
import java.io.Serializable;
public class MeasureModel implements Serializable {
private int width;
private int height;
private String frameUrl;
private int status;//1成功 2失败
@Expose(serialize = false, deserialize = false)
private long duration;
public long getDuration() {
return duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public String getFrameUrl() {
return frameUrl;
}
public void setFrameUrl(String frameUrl) {
this.frameUrl = frameUrl;
}
public boolean isScale() {
return (float)height / width > 3;
}
}
package com.yumeng.libbaseProject.listener;
/**
* Created by YoKey on 16/10/9.
*/
public interface IndexableEntity {
String getFieldIndexBy();
void setFieldIndexBy(String indexField);
void setFieldPinyinIndexBy(String pinyin);
}
package com.yumeng.libbaseProject.manager;
import android.content.Context;
import android.os.SystemClock;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Chronometer;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.yumeng.libbaseProject.R;
import com.yumeng.libbaseProject.helper.measure.MeasureHelper;
import com.yumeng.libcommon.utils.ViewUtils;
import com.yumeng.libcommonview.theme.Theme;
import com.yumeng.libcommonview.view.CommonPopupWindow;
import com.yumeng.libcommonview.view.recordWaveView.RecordWaveView;
public class DialogManager {
private CommonPopupWindow window;
private Context mContext;
private RecordWaveView recordWaveView;
private Chronometer time;
private TextView tvTips;
private View anchor;
private LinearLayout llBg;
public DialogManager(Context context) {
mContext = context;
}
public void setAnchor(View anchor) {
this.anchor = anchor;
window = new CommonPopupWindow(mContext, R.layout.dialog_audio, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {
@Override
protected void initView() {
View view = getContentView();
recordWaveView = ViewUtils.findViewsById(view, R.id.recordWaveView);
time = ViewUtils.findViewsById(view, R.id.time);
tvTips = ViewUtils.findViewsById(view, R.id.tips);
llBg = ViewUtils.findViewsById(view, R.id.llBg);
}
@Override
protected void initEvent() {
}
};
}
public void showRecordingDialog() {
recordWaveView.setNormalData();
setBasicColor();
int windowsPos[] = MeasureHelper.INSTANCE.calculatePopWindowPos(anchor,window.getContentView());
window.showAtLocation(anchor, Gravity.NO_GRAVITY, windowsPos[0], windowsPos[1]);
time.setBase(SystemClock.elapsedRealtime());
time.start();
}
public void dimissDialog() {
window.getPopupWindow().dismiss();
recordWaveView.stop();
}
public void setVolume(int volume) {
// vlVoice.setVolume(volume);
recordWaveView.setVolume(volume);
}
public void stopTime() {
time.stop();
}
public Chronometer getTime() {
return time;
}
public void updateTips(String tips) {
tvTips.setText(tips);
}
public void setBgSelector(boolean selector){
llBg.setSelected(selector);
if(selector){
recordWaveView.setmWaveColor(mContext.getResources().getColor(R.color.white));
time.setTextColor(mContext.getResources().getColor(R.color.white));
}else{
setBasicColor();
}
}
private void setBasicColor() {
time.setTextColor(Theme.Companion.getThemeColor());
recordWaveView.setmWaveColor(Theme.Companion.getThemeColor());
// switch (Theme.Companion.getThemePosition()){
// case 1:
// time.setTextColor(mContext.getResources().getColor(R.color.basic_theme_colors_blue));
// recordWaveView.setmWaveColor(mContext.getResources().getColor(R.color.basic_theme_colors_blue));
// break;
// default:
// time.setTextColor(mContext.getResources().getColor(R.color.basic_theme_colors));
// recordWaveView.setmWaveColor(mContext.getResources().getColor(R.color.basic_theme_colors));
// break;
// }
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.model;
import com.yumeng.libbaseProject.listener.IndexableEntity;
import java.io.Serializable;
/**
* Created by yumeng on 2018/4/27.
*/
public class NationCodeBean implements Serializable, IndexableEntity {
private String name;
private String cn_name;
private String dial_code;
private String code;
private String headWord;
private String price;
private String pinyin;
public String getCn_name() {
return cn_name;
}
public void setCn_name(String cn_name) {
this.cn_name = cn_name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDial_code() {
return dial_code;
}
public void setDial_code(String dial_code) {
this.dial_code = dial_code;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getHeadWord() {
return name.substring(0, 1).toUpperCase();
}
public void setHeadWord(String headWord) {
this.headWord = headWord;
}
@Override
public String getFieldIndexBy() {
return name;
}
@Override
public void setFieldIndexBy(String indexField) {
this.pinyin = indexField;
}
@Override
public void setFieldPinyinIndexBy(String pinyin) {
this.pinyin = pinyin;
}
}
package com.yumeng.libbaseProject.model;
import java.io.Serializable;
/**
* Created by Administrator on 2018/3/21.
*/
public class UserInfo implements Serializable {
private String token;//用户token
private int expires_in;//过期时间
private String refreshToken;
private String token_type;
private String id;
private String avatar;//头像
private String mobile;
private String name;
private String introduce;
private String uid;
private String sex;
private String address;//家庭住址
private String region;//地区
private String country;//国家
private String dialCode;
private boolean authenticatedFlag;
private long dynamicNum;
private long fansNum;
private long focusNum;
private boolean uidModifyFlag;
public String getUid() {
return uid;
}
public boolean isUidModifyFlag() {
return uidModifyFlag;
}
public void setUidModifyFlag(boolean uidModifyFlag) {
this.uidModifyFlag = uidModifyFlag;
}
public void setUid(String uid) {
this.uid = uid;
}
public boolean isAuthenticatedFlag() {
return authenticatedFlag;
}
public void setAuthenticatedFlag(boolean authenticatedFlag) {
this.authenticatedFlag = authenticatedFlag;
}
public long getDynamicNum() {
return dynamicNum;
}
public void setDynamicNum(long dynamicNum) {
this.dynamicNum = dynamicNum;
}
public long getFansNum() {
return fansNum;
}
public void setFansNum(long fansNum) {
this.fansNum = fansNum;
}
public long getFocusNum() {
return focusNum;
}
public void setFocusNum(long focusNum) {
this.focusNum = focusNum;
}
public String getDialCode() {
return dialCode;
}
public void setDialCode(String dialCode) {
this.dialCode = dialCode;
}
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public int getExpires_in() {
return expires_in;
}
public void setExpires_in(int expires_in) {
this.expires_in = expires_in;
}
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
public String getToken_type() {
return token_type;
}
public void setToken_type(String token_type) {
this.token_type = token_type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIntroduce() {
return introduce;
}
public void setIntroduce(String introduce) {
this.introduce = introduce;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public boolean isMale() {
return sex.equals("0");
}
}
package com.yumeng.libbaseProject.router
import android.content.Context
import com.sankuai.waimai.router.Router
object RouterManger {
fun startLoginActivity(context: Context?) {
Router.startUri(context, RouterScheme.LoginActivityPath)
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.router
object RouterScheme {
const val LoginActivityPath = "/login"
const val MainActivity = "/main"
const val NewsAuthorHomeActivity = "/author_home"
}
\ No newline at end of file
package com.yumeng.libbaseProject.service.ResponseModel;
import android.text.TextUtils;
import com.alibaba.fastjson.JSON;
import com.chad.library.adapter.base.entity.MultiItemEntity;
import com.yumeng.libbase.helper.DataHelper;
import org.jetbrains.annotations.Nullable;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
//多布局item bean
public class TestResponse implements MultiItemEntity, Serializable {
public static final int ITEM_INFO_CENTER_PIC_NEWS = 0; //推荐 中间一个大图
public static final int ITEM_INFO_PIC_RIGHT_NEWS = 1; //推荐 文字加右边一个小图
public static final int ITEM_INFO_THREE_PICS_NEWS = 2; //推荐 3个小图加文字
public static final int ITEM_INFO_CENTER_VIDEO_NEWS = 3; //视频
public static final int ITEM_INFO_FOCUS_CENTER_VIDEO_NEWS = 4; //关心 中间一个大图
public static final int ITEM_INFO_FOCUS_PIC_RIGHT_NEWS = 5; //关心 文字加右边一个小图
public static final int ITEM_INFO_FOCUS_THREE_PICS_NEWS = 6; //关心 3个小图加文字
private String id; //文章id
private String authId; //作者id
private String title; //文章标题
private String type; //文章类型0表示图文,1表示音视频
private String comments; //评论数
private String collections; //收藏数
private String shares; //分享数
private String video; //音视频
private String coverimg; //封面图
private String userId; //关注者id (待删除)
private String authName; //作者名称
private long createDate; //创建日期
private boolean hadFocus; //是否关注
private String avatar; //
private boolean hadUpvote;//是否点赞
private String upvote;//点赞数量
private String content;
private List<String> coverimgList; //
private Boolean isTop = false;
private boolean catalogFollow = false;//后续可以请求服务端关注和推荐|其他栏目接口新增该类似字段,以免需要一次for循环
public boolean isCatalogFollow() {
return catalogFollow;
}
public void setCatalogFollow(boolean catalogFollow) {
this.catalogFollow = catalogFollow;
}
@Override
public int hashCode() {
int result = 1;
if (TextUtils.isEmpty(id)) {
result = 31 * result + authId.hashCode();
} else {
result = 31 * result + id.hashCode();
}
result = 31 * result + Long.valueOf(createDate).hashCode();
return result;
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof TestResponse)) {
return false;
}
TestResponse other = (TestResponse) obj;
if (TextUtils.isEmpty(id)) {
return authId.equals(other.getAuthId()) && createDate == other.createDate;
} else {
return id.equals(other.getId()) && createDate == other.createDate;
}
}
@Override
public String toString() {
return "InformationMultiItemBean{" +
", id='" + id + '\'' +
", authId='" + authId + '\'' +
", title='" + title + '\'' +
", type='" + type + '\'' +
", comments='" + comments + '\'' +
", collections='" + collections + '\'' +
", shares='" + shares + '\'' +
", video='" + video + '\'' +
", coverimg='" + coverimg + '\'' +
", userId='" + userId + '\'' +
", authName='" + authName + '\'' +
", createDate=" + createDate +
", hadFocus=" + hadFocus +
", avatar='" + avatar + '\'' +
", coverimgList=" + coverimgList +
", upvote=" + upvote +
", hadUpvote=" + hadUpvote +
'}';
}
@Override
public int getItemType() {
return 1;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAuthId() {
return authId;
}
public void setAuthId(String authId) {
this.authId = authId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getComments() {
if (TextUtils.isEmpty(comments)) {
return "0";
}
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public String getCollections() {
return collections;
}
public void setCollections(String collections) {
this.collections = collections;
}
public String getShares() {
return shares;
}
public void setShares(String shares) {
this.shares = shares;
}
public String getVideo() {
return video;
}
public void setVideo(String video) {
this.video = video;
}
public String getCoverimg() {
return coverimg;
}
public void setCoverimg(String coverimg) {
this.coverimg = coverimg;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getAuthName() {
return authName;
}
public void setAuthName(String authName) {
this.authName = authName;
}
public long getCreateDate() {
return createDate;
}
public void setCreateDate(long createDate) {
this.createDate = createDate;
}
public boolean isHadFocus() {
return hadFocus;
}
public void setHadFocus(boolean hadFocus) {
this.hadFocus = hadFocus;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public List<String> getCoverImgList() {
if (coverimgList == null) {
if (coverimg != null) {
coverimgList = JSON.parseArray(coverimg, String.class);
} else {
coverimgList = new ArrayList<>();
}
}
return coverimgList;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public boolean isHadUpvote() {
return hadUpvote;
}
public void setHadUpvote(boolean hadUpvote) {
this.hadUpvote = hadUpvote;
}
public String getUpvote() {
if (upvote == null) {
return "0";
}
return upvote;
}
public boolean isVideo() {
return type != null && !type.equals("0");
}
public void setUpvote(String upvote) {
this.upvote = upvote;
}
public void setCoverimgList(List<String> coverimgList) {
this.coverimgList = coverimgList;
}
public Boolean getTop() {
return isTop;
}
public void setTop(Boolean top) {
isTop = top;
}
}
package com.yumeng.libbaseProject.service
import com.yumeng.libbaseProject.service.ResponseModel.TestResponse
import com.yumeng.libcore.response.BaseResponse
import com.yumeng.libcore.response.BaseResponseDataList
import com.yumeng.libcore.service.Api
import okhttp3.RequestBody
import retrofit2.http.*
interface Service {
companion object {
const val BASE_DOMAIN_NAME = "base_domain_name"
}
/**
* 获取文章关注列表
* TODO
*/
@Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
@GET("article/articleMobile")
suspend fun getArticles(
@Query("pageNo") pageNo: Int,
@Query("catalogId") catalogId: String,
@Query("lastTime") lastTime: Long,
@Query("pageSize") pageSize: Int = 30
): BaseResponse<BaseResponseDataList<TestResponse>>
//
// /**
// * 获取文章栏目
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @GET("article/articleMobile")
// suspend fun getArticles(
// @Query("pageNo") pageNo: Int,
// @Query("catalogId") catalogId: String,
// @Query("lastTime") lastTime: Long,
// @Query("pageSize") pageSize: Int = 30
// ): BaseResponse<NewsResponse>
//
// /**
// * 按搜索获取文章栏目
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @GET("article/search")
// suspend fun getSearchArticles(
// @Query("pageNo") pageNo: Int,
// @Query("keyword") keyword: String,
// @Query("lastTime") lastTime: Long,
// @Query("pageSize") pageSize: Int = 30
// ): BaseResponse<NewsResponse>
//
// /**
// * 获取推荐顶置接口
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @GET("article/tops")
// suspend fun getArticleTop(): BaseResponse<List<InformationMultiItemBean>>
//
// /**
// * 获取文章目录
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @GET("catalog")
// suspend fun getCatalog(
// @Query("type") catalogType: Int = 1
// ): BaseResponse<List<ChannelBean>>
//
// /**
// * 获取消息红点提示
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @GET("articleNotice/newFlag")
// suspend fun getNoticeNewFlag(): BaseResponse<NewsNoticeFlagResponse>
//
// /**
// * 设置目录顺序
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @PUT("catalog")
// suspend fun setCatalog(
// @Body body: RequestBody
// ): BaseResponse<String>
//
// /**
// * 清空资讯通知列表
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @DELETE("articleNotice/clear")
// suspend fun clearMessageNotice(): BaseResponse<String>
//
// /**
// * 获取资讯通知列表
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @GET("articleNotice/list")
// suspend fun getMessagesNotice(
// @Query("pageNo") pageNo: Int,
// @Query("pageSize") pageSize: Int = 30
// ): BaseResponse<MessageNoticeListResponse>
//
// /**
// * 获取文章详情
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @GET("article/{id}")
// suspend fun getNewsDetail(
// @Path("id") id: String
// ): BaseResponse<InformationMultiItemBean>
//
// /**
// * 获取文章评论列表
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @GET("comment/{id}")
// suspend fun getNewsDetailComments(
// @Path("id") id: String,
// @Query("pageNo") pageNo: Int,
// @Query("pageSize") pageSize: Int = 30
// ): BaseResponse<NewsCommentListResponse>
//
// /**
// * 获取文章评论列表
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @GET("reply/{commentId}")
// suspend fun getSubComments(
// @Path("commentId") id: String,
// @Query("pageNo") pageNo: Int,
// @Query("pageSize") pageSize: Int = 30
// ): BaseResponse<NewsCommentSubListResponse>
//
// /**
// * 关注自媒体
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @POST("userFocus")
// suspend fun following(
// @Body body: RequestBody
// ): BaseResponse<FollowingResponse>
//
//
// /**
// * 发送一级评论
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @POST("comment")
// suspend fun addComment(
// @Body body: RequestBody
// ): BaseResponse<NewsCommentBean>
//
// /**
// * 发送二级评论
// * TODO 这个需要搞
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @POST("reply")
// suspend fun addSubComment(
// @Body body: RequestBody
// ): BaseResponse<NewsSubCommentBean>
//
//
// /**
// * 评论点赞/取消点赞
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @POST("comment/upvote")
// suspend fun thumbsUp(
// @Body body: RequestBody
// ): BaseResponse<ThumbsUpResponse>
//
// /**
// * 二级评论点赞/取消点赞
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @POST("reply/upvote")
// suspend fun replyThumbsUp(
// @Body body: RequestBody
// ): BaseResponse<ThumbsUpResponse>
//
// /**
// * 文章点赞
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @POST("article/upvote")
// suspend fun articleThumbsUp(
// @Body body: RequestBody
// ): BaseResponse<ThumbsUpResponse>
//
// /**
// * 文章、投诉|收藏等
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @POST("article/operate")
// suspend fun operateArticle(
// @Body body: RequestBody
// ): BaseResponse<Any>
//
//
// /**
// * 获取关注列表
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @GET("userFocus")
// suspend fun getFollowings(
// @Query("pageNo") pageNo: Int,
// @Query("pageSize") pageSize: Int = 30
// ): BaseResponse<NewsResponse>
//
// /**
// * 获取粉丝列表
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @GET("userFocus/fans")
// suspend fun getFans(
// @Query("pageNo") pageNo: Int,
// @Query("pageSize") pageSize: Int = 30
// ): BaseResponse<NewsResponse>
//
// /**
// * 获取关注列表
// * TODO
// */
// @Headers(Api.URL_NAME + BASE_DOMAIN_NAME)
// @GET("userFocus/search")
// suspend fun searchFollowings(
// @Query("keyword") keyword : String
// ): BaseResponse<NewsResponse>
}
\ No newline at end of file
package com.yumeng.libbaseProject.service.http
import com.yumeng.libbaseProject.BuildConfig
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
abstract class BaseRetrofitClient {
companion object {
private const val TIME_OUT = 5L
}
private val client: OkHttpClient
get() {
// val builder = RetrofitUrlManager.getInstance().with(OkHttpClient.Builder())
val builder = OkHttpClient.Builder()
.readTimeout(TIME_OUT, TimeUnit.SECONDS)
.connectTimeout(TIME_OUT, TimeUnit.SECONDS)
val logging = HttpLoggingInterceptor()
if (BuildConfig.DEBUG) {
logging.level = HttpLoggingInterceptor.Level.BODY
} else {
logging.level = HttpLoggingInterceptor.Level.BASIC
}
builder.addInterceptor(BaseUrlInterceptor())
builder.addInterceptor(logging)
handleBuilder(builder)
return builder.build()
}
protected abstract fun handleBuilder(builder: OkHttpClient.Builder)
private val mRetrofit: Retrofit by lazy {
Retrofit.Builder()
.client(client)
.addConverterFactory(GsonConverterFactory.create())
// .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
// .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke())
.baseUrl(BuildConfig.BASE_URL)
.build()
}
fun <S> getService(serviceClass: Class<S>): S {
return mRetrofit.create(serviceClass)
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.service.http
import android.util.Log
import com.yumeng.libbaseProject.BuildConfig
import com.yumeng.libbaseProject.service.Service
import com.yumeng.libcore.service.Api
import okhttp3.HttpUrl
import okhttp3.Interceptor
import okhttp3.Response
class BaseUrlInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
//获取request
val request = chain.request()
//从request中获取原有的HttpUrl实例oldHttpUrl
val oldHttpUrl = request.url()
//获取request的创建者builder
val builder = request.newBuilder()
//从request中获取headers,通过给定的键url_name
val headerValues:List<String>? = request.headers(Api.URL_NAME_UNIT)
if (headerValues != null && headerValues.isNotEmpty()) {
//如果有这个header,先将配置的header删除,因此header仅用作app和okhttp之间使用
builder.removeHeader(Api.URL_NAME_UNIT)
//匹配获得新的BaseUrl
val newBaseUrl = when (headerValues[0]) {
Service.BASE_DOMAIN_NAME -> {
HttpUrl.parse(BuildConfig.BASE_URL)
}
// UserService.USER_DOMAIN_NAME -> {
// HttpUrl.parse(BuildConfig.BASE_URL)
// }
else -> oldHttpUrl
}
Log.e("BaseUrlInterceptor","newBaseUrl:-> $newBaseUrl")
//重建新的HttpUrl,修改需要修改的url部分
newBaseUrl?.apply {
val newFullUrl = oldHttpUrl.newBuilder()
.scheme(newBaseUrl.scheme())//更换网络协议
.host(newBaseUrl.host())//更换主机名
.port(newBaseUrl.port())//更换端口
.build()
return chain.proceed(builder.url(newFullUrl).build());
}
}
return chain.proceed(request);
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.service.http
import com.franmontiel.persistentcookiejar.PersistentCookieJar
import com.franmontiel.persistentcookiejar.cache.SetCookieCache
import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor
import com.yumeng.libbaseProject.BuildConfig
import com.yumeng.libbaseProject.Contants.Constants
import com.yumeng.libbaseProject.application.MyApplication
import com.yumeng.libbaseProject.model.UserInfo
import com.yumeng.libbaseProject.service.Service
import com.yumeng.libcommon.context.AppContextWrapper
import com.yumeng.libcore.utils.NetWorkUtils
import okhttp3.Cache
import okhttp3.CacheControl
import okhttp3.OkHttpClient
import java.io.File
object Net : BaseRetrofitClient() {
val service by lazy {
getService(Service::class.java)
}
private val cookieJar by lazy {
PersistentCookieJar(
SetCookieCache(),
SharedPrefsCookiePersistor(AppContextWrapper.getApplicationContext())
)
}
private val userInfo: UserInfo? get() = MyApplication.CURRENT_USER
override fun handleBuilder(builder: OkHttpClient.Builder) {
val httpCacheDirectory =
File(AppContextWrapper.getApplicationContext().cacheDir, "responses")
val cacheSize = 10 * 1024 * 1024L // 10 MiB
val cache = Cache(httpCacheDirectory, cacheSize)
builder.cache(cache)
.cookieJar(cookieJar)
.addInterceptor { chain ->
var request = chain.request()
if (!NetWorkUtils.isNetworkAvailable(AppContextWrapper.getApplicationContext())) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build()
}
val authorizedUrlBuilder = request.url()
.newBuilder()
.scheme(request.url().scheme())
.host(request.url().host())
val build = request.newBuilder()
.method(request.method(), request.body())
.url(authorizedUrlBuilder.build())
// .addHeader("platform", "1")
// .addHeader("deviceId", "a855cb900e112b06")
.addHeader("versionNo", BuildConfig.VERSION_NAME)
.addHeader("versionCode", BuildConfig.VERSION_CODE.toString())
// .addHeader(Constants.LANGUAGE_TYPE, "zh_simple")
userInfo?.token?.let {
build.addHeader(Constants.AUTHORIZATION, it)
}
val response = chain.proceed(build.build())
if (!NetWorkUtils.isNetworkAvailable(AppContextWrapper.getApplicationContext())) {
val maxAge = 60 * 60
response.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, max-age=$maxAge")
.build()
} else {
val maxStale = 60 * 60 * 24 * 28 // tolerate 4-weeks stale
response.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, only-if-cached, max-stale=$maxStale")
.build()
}
response
}
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.service.repository
import com.yumeng.libbaseProject.service.ResponseModel.TestResponse
import com.yumeng.libbaseProject.service.http.Net
import com.yumeng.libcore.IResult
import com.yumeng.libcore.base.BaseRepository
import com.yumeng.libcore.response.BaseResponseDataList
class NewsDetailRepository : BaseRepository() {
//获取文章详情
suspend fun getArticles(id: String): IResult<BaseResponseDataList<TestResponse>> {
return safeApiCall(
call = { executeResponse(Net.service.getArticles(pageNo = 1,catalogId = id,lastTime = 0L)) },
errorMessage = ""
)
}
//
// //评论点赞
// suspend fun thumbsUp(commentId: String): IResult<ThumbsUpResponse> {
// return safeApiCall(
// call = { executeResponse(
// Net.service.thumbsUp(
// RequestBodyHelper.createJsonBody(
// CommentThumpsUpRequestModel(commentId)
// )
// )
// )},
// errorMessage = ""
// )
// }
}
\ No newline at end of file
package com.yumeng.libbaseProject.themeUtils
import android.content.Context
import android.graphics.drawable.Drawable
import androidx.core.content.ContextCompat
import com.yumeng.libbaseProject.R
import com.yumeng.libcommonview.theme.Theme
object ThemeCommon {
fun getThemeCircleDrawable(context: Context): Drawable? {
return when (Theme.themePosition) {
0 -> {
ContextCompat.getDrawable(context, R.drawable.shape_circle)
}
else -> {
ContextCompat.getDrawable(context, R.drawable.shape_circle)
}
}
}
fun getFileAssistantSmall(): Int {
return when (Theme.themePosition) {
0 -> {
R.mipmap.ic_file_assistant
}
else -> {
R.mipmap.ic_file_assistant
}
}
}
fun getSystemNotification(): Int {
return when (Theme.themePosition) {
0 -> {
R.drawable.ic_chat_system_not
}
else -> {
R.drawable.ic_chat_system_not
}
}
}
fun getTmpChatBoxDrable(): Int {
return when (Theme.themePosition) {
0 -> {
R.drawable.ic_tmp_chat
}
else -> {
R.drawable.ic_tmp_chat
}
}
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.utils;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.os.Build;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewAnimationUtils;
import androidx.core.view.ViewCompat;
import androidx.core.view.ViewPropertyAnimatorListener;
/**
* @author Miguel Catalan Bañuls
*/
public class AnimationUtil {
public static int ANIMATION_DURATION_SHORT = 150;
public static int ANIMATION_DURATION_MEDIUM = 400;
public static int ANIMATION_DURATION_LONG = 800;
public interface AnimationListener {
/**
* @return true to override parent. Else execute Parent method
*/
boolean onAnimationStart(View view);
boolean onAnimationEnd(View view);
boolean onAnimationCancel(View view);
}
public static void crossFadeViews(View showView, View hideView) {
crossFadeViews(showView, hideView, ANIMATION_DURATION_SHORT);
}
public static void crossFadeViews(View showView, final View hideView, int duration) {
fadeInView(showView, duration);
fadeOutView(hideView, duration);
}
public static void fadeInView(View view) {
fadeInView(view, ANIMATION_DURATION_SHORT);
}
public static void fadeInView(View view, int duration) {
fadeInView(view, duration, null);
}
public static void fadeInView(View view, int duration, final AnimationListener listener) {
view.setVisibility(View.VISIBLE);
view.setAlpha(0f);
ViewPropertyAnimatorListener vpListener = null;
if (listener != null) {
vpListener = new ViewPropertyAnimatorListener() {
@Override
public void onAnimationStart(View view) {
if (!listener.onAnimationStart(view)) {
view.setDrawingCacheEnabled(true);
}
}
@Override
public void onAnimationEnd(View view) {
if (!listener.onAnimationEnd(view)) {
view.setDrawingCacheEnabled(false);
}
}
@Override
public void onAnimationCancel(View view) {
}
};
}
ViewCompat.animate(view).alpha(1f).setDuration(duration).setListener(vpListener);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static void reveal(final View view, final AnimationListener listener) {
int cx = view.getWidth() - (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 24, view.getResources().getDisplayMetrics());
int cy = view.getHeight() / 2;
int finalRadius = Math.max(view.getWidth(), view.getHeight());
Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius);
view.setVisibility(View.VISIBLE);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
listener.onAnimationStart(view);
}
@Override
public void onAnimationEnd(Animator animation) {
listener.onAnimationEnd(view);
}
@Override
public void onAnimationCancel(Animator animation) {
listener.onAnimationCancel(view);
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
anim.start();
}
public static void fadeOutView(View view) {
fadeOutView(view, ANIMATION_DURATION_SHORT);
}
public static void fadeOutView(View view, int duration) {
fadeOutView(view, duration, null);
}
public static void fadeOutView(View view, int duration, final AnimationListener listener) {
ViewCompat.animate(view).alpha(0f).setDuration(duration).setListener(new ViewPropertyAnimatorListener() {
@Override
public void onAnimationStart(View view) {
if (listener == null || !listener.onAnimationStart(view)) {
view.setDrawingCacheEnabled(true);
}
}
@Override
public void onAnimationEnd(View view) {
if (listener == null || !listener.onAnimationEnd(view)) {
view.setVisibility(View.GONE);
view.setDrawingCacheEnabled(false);
}
}
@Override
public void onAnimationCancel(View view) {
}
});
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.view;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.yumeng.libcommon.utils.ServiceUtil;
public class InputAwareLayout extends KeyboardAwareLinearLayout implements KeyboardAwareLinearLayout.OnKeyboardShownListener {
private InputView current;
public InputAwareLayout(Context context) {
this(context, null);
}
public InputAwareLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public InputAwareLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
addOnKeyboardShownListener(this);
}
@Override
public void onKeyboardShown() {
hideAttachedInput(true);
}
public void show(@NonNull final EditText imeTarget, @NonNull final InputView input) {
if (isKeyboardOpen()) {
hideSoftkey(imeTarget, new Runnable() {
@Override
public void run() {
hideAttachedInput(true);
input.show(getKeyboardHeight(), true);
current = input;
}
});
} else {
if (current != null) current.hide(true);
input.show(getKeyboardHeight(), current != null);
current = input;
}
}
public InputView getCurrentInput() {
return current;
}
public void hideCurrentInput(EditText imeTarget) {
if (isKeyboardOpen()) hideSoftkey(imeTarget, null);
else hideAttachedInput(false);
}
public void hideAttachedInput(boolean instant) {
if (current != null) current.hide(instant);
current = null;
}
public boolean isInputOpen() {
return (isKeyboardOpen() || (current != null && current.isShowing()));
}
public void showSoftkey(final EditText inputTarget) {
postOnKeyboardOpen(new Runnable() {
@Override
public void run() {
hideAttachedInput(true);
}
});
inputTarget.post(new Runnable() {
@Override
public void run() {
inputTarget.requestFocus();
ServiceUtil.getInputMethodManager(inputTarget.getContext()).showSoftInput(inputTarget, 0);
}
});
}
public void hideSoftkey(final EditText inputTarget, @Nullable Runnable runAfterClose) {
if (runAfterClose != null) postOnKeyboardClose(runAfterClose);
ServiceUtil.getInputMethodManager(inputTarget.getContext())
.hideSoftInputFromWindow(inputTarget.getWindowToken(), 0);
}
public interface InputView {
void show(int height, boolean immediate);
void hide(boolean immediate);
boolean isShowing();
}
}
/**
* Copyright (C) 2014 Open Whisper Systems
* <p>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.yumeng.libbaseProject.view;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.View;
import androidx.appcompat.widget.LinearLayoutCompat;
import com.yumeng.libbaseProject.R;
import com.yumeng.libcommon.utils.ServiceUtil;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
/**
* LinearLayout that, when a view container, will report back when it thinks a soft keyboard
* has been opened and what its height would be.
*/
public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
private static final String TAG = KeyboardAwareLinearLayout.class.getSimpleName();
private final Rect rect = new Rect();
private final Set<OnKeyboardHiddenListener> hiddenListeners = new HashSet<>();
private final Set<OnKeyboardShownListener> shownListeners = new HashSet<>();
private final int minKeyboardSize;
private final int minCustomKeyboardSize;
private final int defaultCustomKeyboardSize;
private final int minCustomKeyboardTopMargin;
private final int statusBarHeight;
private int viewInset;
private boolean keyboardOpen = false;
private int rotation = -1;
public KeyboardAwareLinearLayout(Context context) {
this(context, null);
}
public KeyboardAwareLinearLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public KeyboardAwareLinearLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final int statusBarRes = getResources().getIdentifier("status_bar_height", "dimen", "android");
minKeyboardSize = getResources().getDimensionPixelSize(R.dimen.min_keyboard_size);
minCustomKeyboardSize = getResources().getDimensionPixelSize(R.dimen.min_custom_keyboard_size);
defaultCustomKeyboardSize = getResources().getDimensionPixelSize(R.dimen.default_custom_keyboard_size);
minCustomKeyboardTopMargin = getResources().getDimensionPixelSize(R.dimen.min_custom_keyboard_top_margin);
statusBarHeight = statusBarRes > 0 ? getResources().getDimensionPixelSize(statusBarRes) : 0;
viewInset = getViewInset();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
updateRotation();
updateKeyboardState();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void updateRotation() {
int oldRotation = rotation;
rotation = getDeviceRotation();
if (oldRotation != rotation) {
Log.i(TAG, "rotation changed");
onKeyboardClose();
}
}
private void updateKeyboardState() {
if (isLandscape()) {
if (keyboardOpen) onKeyboardClose();
return;
}
if (viewInset == 0 && Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP)
viewInset = getViewInset();
final int availableHeight = this.getRootView().getHeight() - statusBarHeight - viewInset;
getWindowVisibleDisplayFrame(rect);
final int keyboardHeight = availableHeight - (rect.bottom - rect.top);
if (keyboardHeight > minKeyboardSize) {
if (getKeyboardHeight() != keyboardHeight) setKeyboardPortraitHeight(keyboardHeight);
if (!keyboardOpen) onKeyboardOpen(keyboardHeight);
} else if (keyboardOpen) {
onKeyboardClose();
}
}
@TargetApi(VERSION_CODES.LOLLIPOP)
private int getViewInset() {
try {
Field attachInfoField = View.class.getDeclaredField("mAttachInfo");
attachInfoField.setAccessible(true);
Object attachInfo = attachInfoField.get(this);
if (attachInfo != null) {
Field stableInsetsField = attachInfo.getClass().getDeclaredField("mStableInsets");
stableInsetsField.setAccessible(true);
Rect insets = (Rect) stableInsetsField.get(attachInfo);
return insets.bottom;
}
} catch (NoSuchFieldException nsfe) {
Log.w(TAG, "field reflection error when measuring view inset", nsfe);
} catch (IllegalAccessException iae) {
Log.w(TAG, "access reflection error when measuring view inset", iae);
}
return 0;
}
protected void onKeyboardOpen(int keyboardHeight) {
Log.i(TAG, "onKeyboardOpen(" + keyboardHeight + ")");
keyboardOpen = true;
notifyShownListeners();
}
protected void onKeyboardClose() {
Log.i(TAG, "onKeyboardClose()");
keyboardOpen = false;
notifyHiddenListeners();
}
public boolean isKeyboardOpen() {
return keyboardOpen;
}
public int getKeyboardHeight() {
return isLandscape() ? getKeyboardLandscapeHeight() : getKeyboardPortraitHeight();
}
public boolean isLandscape() {
int rotation = getDeviceRotation();
return rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270;
}
private int getDeviceRotation() {
return ServiceUtil.getWindowManager(getContext()).getDefaultDisplay().getRotation();
}
private int getKeyboardLandscapeHeight() {
return Math.max(getHeight(), getRootView().getHeight()) / 2;
}
private int getKeyboardPortraitHeight() {
int keyboardHeight = PreferenceManager.getDefaultSharedPreferences(getContext())
.getInt("keyboard_height_portrait", defaultCustomKeyboardSize);
//return Util.clamp(keyboardHeight, minCustomKeyboardSize, getRootView().getHeight() - minCustomKeyboardTopMargin);
return Math.min(Math.max(keyboardHeight, minCustomKeyboardSize), getRootView().getHeight() - minCustomKeyboardTopMargin);
}
private void setKeyboardPortraitHeight(int height) {
PreferenceManager.getDefaultSharedPreferences(getContext())
.edit().putInt("keyboard_height_portrait", height).apply();
}
public void postOnKeyboardClose(final Runnable runnable) {
if (keyboardOpen) {
addOnKeyboardHiddenListener(new OnKeyboardHiddenListener() {
@Override
public void onKeyboardHidden() {
removeOnKeyboardHiddenListener(this);
runnable.run();
}
});
} else {
runnable.run();
}
}
public void postOnKeyboardOpen(final Runnable runnable) {
if (!keyboardOpen) {
addOnKeyboardShownListener(new OnKeyboardShownListener() {
@Override
public void onKeyboardShown() {
removeOnKeyboardShownListener(this);
runnable.run();
}
});
} else {
runnable.run();
}
}
public void addOnKeyboardHiddenListener(OnKeyboardHiddenListener listener) {
hiddenListeners.add(listener);
}
public void removeOnKeyboardHiddenListener(OnKeyboardHiddenListener listener) {
hiddenListeners.remove(listener);
}
public void addOnKeyboardShownListener(OnKeyboardShownListener listener) {
shownListeners.add(listener);
}
public void removeOnKeyboardShownListener(OnKeyboardShownListener listener) {
shownListeners.remove(listener);
}
private void notifyHiddenListeners() {
final Set<OnKeyboardHiddenListener> listeners = new HashSet<>(hiddenListeners);
for (OnKeyboardHiddenListener listener : listeners) {
listener.onKeyboardHidden();
}
}
private void notifyShownListeners() {
final Set<OnKeyboardShownListener> listeners = new HashSet<>(shownListeners);
for (OnKeyboardShownListener listener : listeners) {
listener.onKeyboardShown();
}
}
public interface OnKeyboardHiddenListener {
void onKeyboardHidden();
}
public interface OnKeyboardShownListener {
void onKeyboardShown();
}
}
package com.yumeng.libbaseProject.view;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class KeyboardHeightFrameLayout extends FrameLayout implements InputAwareLayout.InputView {
public KeyboardHeightFrameLayout(@NonNull Context context) {
super(context);
}
public KeyboardHeightFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public KeyboardHeightFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public KeyboardHeightFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void show(int height, boolean immediate) {
// TODO
ViewGroup.LayoutParams layoutParams = getLayoutParams();
layoutParams.height = height;
getChildAt(0).setVisibility(VISIBLE);
setVisibility(VISIBLE);
}
@Override
public void hide(boolean immediate) {
setVisibility(GONE);
}
@Override
public boolean isShowing() {
return getVisibility() == VISIBLE;
}
}
package com.yumeng.libbaseProject.view.audioRecorder;
import android.annotation.TargetApi;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaRecorder;
import android.os.Build;
import com.yumeng.libcommon.utils.LogUtils;
import com.yumeng.libcommon.utils.MainThreadUtil;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class AudioCodec {
private static final String TAG = AudioCodec.class.getSimpleName();
private static final int SAMPLE_RATE = 44100;
private static final int SAMPLE_RATE_INDEX = 4;
private static final int CHANNELS = 1;
private static final int BIT_RATE = 32000;
private final int bufferSize;
private final MediaCodec mediaCodec;
private final AudioRecord audioRecord;
private boolean running = true;
private boolean finished = false;
short[] buffer;
private int volume;
private List<Integer> volumes = new ArrayList<>();
public int getVolume() {
return volume;
}
public AudioCodec() throws IOException {
this.bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
this.audioRecord = createAudioRecord(this.bufferSize);
this.mediaCodec = createMediaCodec(this.bufferSize);
this.mediaCodec.start();
try {
audioRecord.startRecording();
} catch (Exception e) {
mediaCodec.release();
throw new IOException(e);
}
}
public synchronized void stop() {
running = false;
while (!finished) MainThreadUtil.wait(this, 0);
}
public List<Integer> getVolumes(){
return volumes;
}
public void start(final OutputStream outputStream) {
new Thread(new Runnable() {
@Override
public void run() {
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
byte[] audioRecordData = new byte[bufferSize];
ByteBuffer[] codecInputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] codecOutputBuffers = mediaCodec.getOutputBuffers();
try {
while (true) {
boolean running = isRunning();
handleCodecInput(audioRecord, audioRecordData, mediaCodec, codecInputBuffers, running);
handleCodecOutput(mediaCodec, codecOutputBuffers, bufferInfo, outputStream);
if (!running) {
volume = 0;
break;
}
}
} catch (IOException e) {
LogUtils.w(TAG, e.toString());
} finally {
mediaCodec.stop();
audioRecord.stop();
mediaCodec.release();
audioRecord.release();
MainThreadUtil.close(outputStream);
setFinished();
}
}
}, AudioCodec.class.getSimpleName()).start();
}
private synchronized boolean isRunning() {
return running;
}
private synchronized void setFinished() {
finished = true;
notifyAll();
}
private boolean isRevert=true;
private void handleCodecInput(AudioRecord audioRecord, byte[] audioRecordData,
MediaCodec mediaCodec, ByteBuffer[] codecInputBuffers,
boolean running) {
int length = audioRecord.read(audioRecordData, 0, audioRecordData.length);
int codecInputBufferIndex = mediaCodec.dequeueInputBuffer(10 * 1000);
if(isRevert) {
isRevert=false;
volume = doublecalculateVolume(audioRecordData);
volumes.add(volume);
}else{
isRevert=true;
}
if (codecInputBufferIndex >= 0) {
ByteBuffer codecBuffer = codecInputBuffers[codecInputBufferIndex];
codecBuffer.clear();
codecBuffer.put(audioRecordData);
mediaCodec.queueInputBuffer(codecInputBufferIndex, 0, length, 0, running ? 0 : MediaCodec.BUFFER_FLAG_END_OF_STREAM);
}
}
public void clearVolumes(){
volumes.clear();
}
private void handleCodecOutput(MediaCodec mediaCodec,
ByteBuffer[] codecOutputBuffers,
MediaCodec.BufferInfo bufferInfo,
OutputStream outputStream)
throws IOException {
int codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
while (codecOutputBufferIndex != MediaCodec.INFO_TRY_AGAIN_LATER) {
if (codecOutputBufferIndex >= 0) {
ByteBuffer encoderOutputBuffer = codecOutputBuffers[codecOutputBufferIndex];
encoderOutputBuffer.position(bufferInfo.offset);
encoderOutputBuffer.limit(bufferInfo.offset + bufferInfo.size);
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != MediaCodec.BUFFER_FLAG_CODEC_CONFIG) {
byte[] header = createAdtsHeader(bufferInfo.size - bufferInfo.offset);
outputStream.write(header);
byte[] data = new byte[encoderOutputBuffer.remaining()];
encoderOutputBuffer.get(data);
outputStream.write(data);
}
encoderOutputBuffer.clear();
mediaCodec.releaseOutputBuffer(codecOutputBufferIndex, false);
} else if (codecOutputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
codecOutputBuffers = mediaCodec.getOutputBuffers();
}
codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
}
private byte[] createAdtsHeader(int length) {
int frameLength = length + 7;
byte[] adtsHeader = new byte[7];
adtsHeader[0] = (byte) 0xFF; // Sync Word
adtsHeader[1] = (byte) 0xF1; // MPEG-4, Layer (0), No CRC
adtsHeader[2] = (byte) ((MediaCodecInfo.CodecProfileLevel.AACObjectLC - 1) << 6);
adtsHeader[2] |= (((byte) SAMPLE_RATE_INDEX) << 2);
adtsHeader[2] |= (((byte) CHANNELS) >> 2);
adtsHeader[3] = (byte) (((CHANNELS & 3) << 6) | ((frameLength >> 11) & 0x03));
adtsHeader[4] = (byte) ((frameLength >> 3) & 0xFF);
adtsHeader[5] = (byte) (((frameLength & 0x07) << 5) | 0x1f);
adtsHeader[6] = (byte) 0xFC;
return adtsHeader;
}
private AudioRecord createAudioRecord(int bufferSize) {
return new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize * 10);
}
private MediaCodec createMediaCodec(int bufferSize) throws IOException {
MediaCodec mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
MediaFormat mediaFormat = new MediaFormat();
mediaFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AAC);
mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, SAMPLE_RATE);
mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, CHANNELS);
mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, bufferSize);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
try {
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
} catch (Exception e) {
LogUtils.w(TAG, e.toString());
mediaCodec.release();
throw new IOException(e);
}
return mediaCodec;
}
// //获取音量
public double getCurrentVolume(byte[] buffer) {
int r = audioRecord.read(buffer, 0, bufferSize);
long v = 0;
// 将 buffer 内容取出,进行平方和运算
for (byte b : buffer) {
v += b * b;
}
// 平方和除以数据总长度,得到音量大小。
double mean = v / (double) r;
return (10 * Math.log10(mean));
}
private int doublecalculateVolume(byte[] buffer) {
double sumVolume = 0.0;
double avgVolume = 0.0;
double volume = 0.0;
for (int i = 0; i < buffer.length; i += 2) {
int v1 = buffer[i] & 0xFF;
int v2 = buffer[i + 1] & 0xFF;
int temp = v1 + (v2 << 8);// 小端
if (temp >= 0x8000) {
temp = 0xffff - temp;
}
sumVolume += Math.abs(temp);
}
avgVolume = sumVolume / buffer.length;
return (int) (Math.log10(1 + avgVolume) * 10);
}
}
package com.yumeng.libbaseProject.view.audioRecorder;
import android.annotation.TargetApi;
import android.os.Build;
import android.text.TextUtils;
import com.yumeng.libcommon.utils.MainThreadUtil;
import com.yumeng.libcommon.utils.ThreadUtil;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class AudioRecorder {
private static final String TAG = AudioRecorder.class.getSimpleName();
private static final ExecutorService executor = ThreadUtil.newDynamicSingleThreadedExecutor();
private AudioCodec audioCodec;
private String filePath;
private BufferedOutputStream mAudioBos;
public AudioRecorder() {
}
public void startRecording(String filePath) {
executor.execute(() -> {
try {
if (audioCodec != null) {
throw new AssertionError("We can only record once at a time.");
}
this.filePath = filePath;
audioCodec = new AudioCodec();
mAudioBos = new BufferedOutputStream(new FileOutputStream(new File(filePath)), 200 * 1024);
audioCodec.start(mAudioBos);
} catch (IOException e) {
e.printStackTrace();
}
});
}
public void release() {
if (audioCodec == null) {
return;
}
audioCodec.clearVolumes();
audioCodec.stop();
audioCodec = null;
try {
if (mAudioBos != null) {
mAudioBos.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (mAudioBos != null) {
try {
mAudioBos.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
mAudioBos = null;
}
}
}
}
public void stopRecording(OnRecordListener onRecordListener) {
executor.execute(() -> {
if (audioCodec == null) {
MainThreadUtil.runOnMain(() -> onRecordListener.onError("MediaRecorder was never initialized successfully!"));
return;
}
List<Double> dilution = dilution(audioCodec.getVolumes());
release();
MainThreadUtil.runOnMain(() -> onRecordListener.onSuccess(dilution));
});
}
private List<Double> dilution(List<Integer> volumes) {
int count = (int) Math.min(Math.round(volumes.size() / 10.0) + 4, 15);
int width = volumes.size() / count;
if ((width + 1) * (count - 1) < volumes.size()) {
width += 1;
}
int index = width / 2;
List<Integer> temps = new ArrayList<>();
for (int i = 0; i < count; i++) {
if ((i + 1) * width < volumes.size()) {
temps.add(volumes.get(i * width + index));
} else {
int lastCount = volumes.size() - i * width;
index = lastCount / 2;
temps.add(volumes.get(i * width + index));
}
}
List<Double> results = new ArrayList<>();
for (Integer temp : temps) {
if(temp<20){
temp=20;
}
double value = (double) (temp - 20) / 18;
results.add(value);
}
return results;
}
public void cancel() {
executor.execute(() -> {
if (!TextUtils.isEmpty(filePath)) {
File file = new File(filePath);
if (file.exists()) {
file.delete();
filePath = null;
}
}
release();
});
}
public String getCurrentFilePath() {
return filePath;
}
public interface OnRecordListener {
public void onError(String content);
public void onSuccess(List<Double> results);
}
//获取当前音量
public int getCurrentVolume() {
if (audioCodec != null)
return audioCodec.getVolume();
return 0;
}
}
package com.yumeng.libbaseProject.view.audioRecorder;
public interface AudioTouchCallback {
void onTouchCallback(int type);
}
package com.yumeng.libbaseProject.view.audioRecorder
import com.yumeng.libbaseProject.R
import com.yumeng.libcommon.context.AppContextWrapper
import com.yumeng.libcommon.utils.ToastUtils
object VoipUtils {
var globalType: String? = null
fun isCalling(): Boolean {
return if (globalType.isNullOrEmpty()) {
false
} else {
if (globalType == "video") {
ToastUtils.getInstance().shortToast(AppContextWrapper.getApplicationContext().getString(
R.string.video_call_is_on_tips))
} else {
ToastUtils.getInstance().shortToast(AppContextWrapper.getApplicationContext().getString(R.string.voice_call_is_on_tips))
}
true
}
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.view.emoji
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import com.vanniktech.emoji.EmojiView
import com.vanniktech.emoji.RecentEmojiManager
import com.vanniktech.emoji.VariantEmojiManager
import com.vanniktech.emoji.listeners.OnEmojiBackspaceClickListener
import com.vanniktech.emoji.listeners.OnEmojiClickListener
import com.yumeng.libbaseProject.R
import com.yumeng.libcommonview.theme.Theme
import kotlinx.android.synthetic.main.widget_emoji_layout.view.*
class MyEmojiView(context: Context?, attrs: AttributeSet? = null) :
LinearLayout(context, attrs) {
private var recentManager: RecentEmojiManager? = null
private var variantManager: VariantEmojiManager? = null
init {
initView()
recentManager = RecentEmojiManager(context!!)
variantManager = VariantEmojiManager(context!!)
}
private fun initView() {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
inflater.inflate(R.layout.widget_emoji_layout, this)
}
fun getRecent(): RecentEmojiManager {
return recentManager!!
}
fun getVariant(): VariantEmojiManager {
return variantManager!!
}
fun setView(onEmojiClickListener: OnEmojiClickListener, onEmojiBackspaceClickListener: OnEmojiBackspaceClickListener) {
val emojiView = EmojiView(
context,
onEmojiClickListener,
null,
recentManager!!,
variantManager!!,
Color.parseColor("#ffffff"),
Color.parseColor("#000000"),
Color.parseColor("#000000"),
Theme.getThemeColor(),
null
)
emojiView.setOnEmojiBackspaceClickListener(onEmojiBackspaceClickListener)
val params =
LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT)
llEmoji.addView(emojiView, params)
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.view.mapview
import android.content.Context
import android.graphics.Bitmap
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.MapView
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
import com.yumeng.libbaseProject.R
import com.yumeng.libcommon.listener.ListenableFuture
import com.yumeng.libcommon.listener.SettableFuture
import kotlinx.android.synthetic.main.widget_map_view.view.*
class AilloMapView : LinearLayout {
private var mapView: MapView? = null
private var imageView: ImageView? = null
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
initialize(context)
}
private fun initialize(context: Context) {
orientation = VERTICAL
val inflate = LayoutInflater.from(context).inflate(R.layout.widget_map_view, this, true)
mapView = inflate.findViewById(R.id.map)
imageView = inflate.findViewById(R.id.imageView)
}
fun display(place: ChatPlace): ListenableFuture<Bitmap> {
val future = SettableFuture<Bitmap>()
this.mapView?.onCreate(null)
this.mapView?.onResume()
this.mapView?.visibility = View.VISIBLE
this.imageView?.visibility = View.GONE
val latLng = LatLng(place.latitude ?: 0.0, place.longitude ?: 0.0)
this.mapView?.getMapAsync { googleMap ->
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 16f))
googleMap.addMarker(MarkerOptions().position(latLng))
googleMap.isBuildingsEnabled = true
googleMap.mapType = GoogleMap.MAP_TYPE_NORMAL
googleMap.uiSettings.setAllGesturesEnabled(false)
googleMap.setOnMapLoadedCallback {
googleMap.snapshot { bitmap ->
future.set(bitmap)
imageView?.setImageBitmap(bitmap)
imageView?.visibility = View.VISIBLE
mapView?.visibility = View.GONE
mapView?.onPause()
mapView?.onDestroy()
}
}
}
this.textView.text = "${place.name}${place.address}"
return future
}
}
\ No newline at end of file
package com.yumeng.libbaseProject.view.mapview
import java.io.Serializable
class ChatPlace() : Serializable {
var name: String? = null
var address: String? = null
var latitude: Double? = null
var longitude: Double? = null
var locationImg: String? = null
var cryptoType: Int = 2//加密消息类型
var fileKey:String?=null
constructor(name: String, address: String, latitude: Double, longitude: Double) : this() {
this.name = name
this.address = address
this.latitude = latitude
this.longitude = longitude
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/linkman_list_anim"
android:animationOrder="normal"
android:delay="0.5" />
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="350"
android:fromYDelta="0"
android:interpolator="@android:anim/decelerate_interpolator"
android:toYDelta="0" />
</set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromYDelta="100%p"
android:toYDelta="0"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="300"
/>
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromYDelta="25"
android:toYDelta="100%p"
android:duration="500"
/>
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- 弹出时动画 -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:interpolator="@android:anim/accelerate_interpolator"
android:fromXScale="1.0"
android:toXScale="1.0"
android:fromYScale="0.0"
android:toYScale="1.0"
android:pivotX="0%"
android:pivotY="100%"
android:fillAfter="false"
android:duration="400"/>
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- 退出时动画效果 -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:interpolator="@android:anim/accelerate_interpolator"
android:fromXScale="1.0"
android:toXScale="1.0"
android:fromYScale="1.0"
android:toYScale="0.0"
android:pivotX="0%"
android:pivotY="100%"
android:fillAfter="false"
android:duration="400"/>
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="500"/>
<translate
android:fromXDelta="-1000"
android:toXDelta="0"
android:duration="500"/>
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="-1000"
android:toYDelta="0" />
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="200"
android:fromXDelta="100.0%p"
android:toXDelta="0.0" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="200"
android:fromXDelta="0.0"
android:toXDelta="100.0%p" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<objectAnimator
android:duration="1"
android:propertyName="elevation"
android:valueTo="0dp"
android:valueType="floatType"/>
</item>
</selector>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<objectAnimator
android:duration="1"
android:propertyName="elevation"
android:valueTo="2dp"
android:valueType="floatType"/>
</item>
</selector>
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Zhihu Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/dracula_bottom_toolbar_apply_text_disable"
android:state_enabled="false"/>
<item android:color="@color/dracula_bottom_toolbar_apply_text"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Zhihu Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/dracula_bottom_toolbar_preview_text_disable"
android:state_enabled="false"/>
<item android:color="@color/dracula_bottom_toolbar_preview_text"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Zhihu Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/dracula_preview_bottom_toolbar_apply_text_disable"
android:state_enabled="false"/>
<item android:color="@color/dracula_preview_bottom_toolbar_apply_text"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/basic_theme_colors" android:state_pressed="true" />
<item android:color="@color/basic_theme_colors" android:state_selected="true" />
<item android:color="@color/basic_theme_colors" android:state_checked="true" />
<item android:color="@color/bottom_icon_bg" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/basic_theme_colors" android:state_pressed="true" />
<item android:color="@color/basic_theme_colors" android:state_selected="true" />
<item android:color="@color/basic_theme_colors" android:state_checked="true" />
<item android:color="@color/color_999999" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" tools:ignore="MissingDefaultResource">
<item android:color="@color/black" android:state_pressed="true" />
<item android:color="@color/black" android:state_selected="true" />
<item android:color="@color/black" android:state_checked="true" />
<item android:color="@color/color_999999" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/basic_theme_colors" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/black" android:state_selected="true"/>
<item android:color="@color/black" android:state_selected="false"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/basic_theme_colors" android:state_selected="true"/>
<item android:color="@color/white" android:state_selected="false"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/white_70" android:state_enabled="false"></item>
<item android:color="@color/white" android:state_enabled="true"></item>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Zhihu Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/zhihu_bottom_toolbar_apply_text_disable"
android:state_enabled="false"/>
<item android:color="@color/zhihu_bottom_toolbar_apply_text"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Zhihu Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/zhihu_bottom_toolbar_preview_text_disable"
android:state_enabled="false"/>
<item android:color="@color/zhihu_bottom_toolbar_preview_text"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Zhihu Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/zhihu_preview_bottom_toolbar_apply_text_disable"
android:state_enabled="false"/>
<item android:color="@color/zhihu_preview_bottom_toolbar_apply_text"/>
</selector>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment