将车聊聊工程代码加入到项目中,保证能跑起来了,后续做架构升级

Signed-off-by: 董宏宇 <martindhy@gmail.com>
This commit is contained in:
董宏宇
2021-10-25 20:29:09 +08:00
parent 3bfad3d31f
commit 17f17ba459
348 changed files with 16837 additions and 9 deletions

View File

@@ -0,0 +1,115 @@
package com.mogo.chat.util
import android.content.Context
import com.alibaba.android.arouter.launcher.ARouter
import com.mogo.chat.R
import com.mogo.chat.aspect.DebugLog
import com.mogo.chat.constant.CALL_TYPE_MATCHING
import com.mogo.chat.constant.CALL_TYPE_VIDEO
import com.mogo.chat.constant.CALL_TYPE_VOICE
import com.mogo.chat.util.sp.getRoomId
import com.mogo.chat.util.sp.getTalkTime
import com.mogo.chat.util.sp.recordCallTime
import com.mogo.commons.AbsMogoApplication
import com.mogo.eagle.core.data.constants.MogoServicePaths
import com.mogo.service.IMogoServiceApis
import com.mogo.service.analytics.IMogoAnalytics
const val TRACK_APP_ENTER = "appenterfront"
const val TRACK_PHONE_CALL_CLICK = "carchat_carphone_call_click"
const val TRACK_VIDEO_CALL_CLICK = "carchat_carphone_video_click"
const val TRACK_CANCEL_CALL_CLICK = "carchat_cancel_call_click"
const val TRACK_MATCH_SUCCESS = "carchat_carphonecall_match_success"
const val TRACK_MATCH_FAIL = "carchat_carphonecall_match_fail"
const val TRACK_MATCH_CANCEL = "carchat_carphonecall_match_cancel_click"
private var trackRouter: IMogoAnalytics? = null
//自定义埋点
@DebugLog
fun trackNormalEvent(
event: String,
data: MutableMap<String, Any>?) {
track(event,data)
}
private fun track(eventType: String, data: MutableMap<String, Any>? = hashMapOf()) {
if (trackRouter == null) {
val aRouter = ARouter.getInstance().build(MogoServicePaths.PATH_SERVICE_APIS).navigation()
if (aRouter is IMogoServiceApis) {
trackRouter = aRouter.analyticsApi
}
}
trackRouter!!.track(eventType, data)
}
@DebugLog
fun trackAppEnter(type: String, context: Context = AbsMogoApplication.getApp().applicationContext) {
trackNormalEvent(
TRACK_APP_ENTER,
mutableMapOf(
"from" to type,
"appname" to context.getString(R.string.app_name),
"appversion" to context.packageManager.getPackageInfo(
context.packageName,
0
).versionName
)
)
}
//todo
@DebugLog
fun trackCall(callType: Int, type: Int) {
//记录开始语音、直播时间
recordCallTime()
when (callType) {
CALL_TYPE_VOICE -> {
trackNormalEvent(
TRACK_PHONE_CALL_CLICK,
mutableMapOf("type" to type, "type_of_call" to "direct")
)
}
CALL_TYPE_MATCHING -> {
trackNormalEvent(
TRACK_PHONE_CALL_CLICK,
mutableMapOf("type" to type, "type_of_call" to "match")
)
}
CALL_TYPE_VIDEO -> {
trackNormalEvent(TRACK_VIDEO_CALL_CLICK, mutableMapOf("type" to type))
}
else -> {
trackNormalEvent(TRACK_PHONE_CALL_CLICK, mutableMapOf("type" to type))
}
}
}
//todo
@DebugLog
fun trackHangUp(callType: Int, source: String = "1") {
when (callType) {
CALL_TYPE_VOICE -> {
trackNormalEvent(
TRACK_CANCEL_CALL_CLICK,
mutableMapOf(
"roomId" to getRoomId(),
"carphone_call_duration" to getTalkTime(),
"type_of_call" to "direct",
"source" to source
)
)
}
CALL_TYPE_MATCHING -> {
trackNormalEvent(
TRACK_CANCEL_CALL_CLICK,
mutableMapOf(
"roomId" to getRoomId(),
"carphone_call_duration" to getTalkTime(),
"type_of_call" to "match",
"source" to source
)
)
}
}
}

View File

@@ -0,0 +1,61 @@
package com.mogo.chat.util
import com.mogo.chat.constant.TAG
import kotlinx.coroutines.*
import java.util.*
import kotlin.concurrent.timerTask
class CallTimer private constructor() {
companion object {
private const val TIMER_RATE = 1000.toLong()//每隔1秒刷新一次时间
val callTimer by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
CallTimer()
}
}
private var mStartTime: Long = 0
private var start: Boolean = false
private var timer: Timer? = null
private var job: Job? = null
private var timerRate: ((Long) -> Unit)? = null //暂时仅有一处使用时间记录,后续如果有多处再使用集合
private var onStop: (() -> Unit)? = null //暂时仅有一处使用时间记录,后续如果有多处再使用集合
fun registerTimerRate(timerRate: ((Long) -> Unit), onStop:() -> Unit) {
this.timerRate = timerRate
this.onStop = onStop
}
fun start() {
if (start) {
log(TAG, "start : $start")
return
}
start = true
job = GlobalScope.async(Dispatchers.Default) {
if (timer == null) {
timer = Timer()
}
mStartTime = System.currentTimeMillis()
timer?.schedule(timerTask {
val timeLong = System.currentTimeMillis() - mStartTime
log(TAG, "times : $timeLong")
timerRate?.invoke(timeLong)
}, 0, TIMER_RATE)
}
}
fun stop() {
if (start) {
onStop?.invoke()
job?.cancel()
timer?.cancel()
timer = null
mStartTime = 0
start = false
}
}
}

View File

@@ -0,0 +1,36 @@
package com.mogo.chat.util
const val SPACE_TIME = 1500
var lastClickTime = 0L
var lastViewClickTime = 0L
var viewId: Int = 0
fun isDoubleClick(view: Int): Boolean {
val time = System.currentTimeMillis()
val timeD = time - lastViewClickTime
if (timeD < SPACE_TIME && viewId == view) {
return true
}
lastViewClickTime = time
viewId = view
return false
}
fun isDoubleClick(): Boolean {
if (System.currentTimeMillis() - lastClickTime < SPACE_TIME) {
return true
}
lastClickTime = System.currentTimeMillis()
return false
}
fun isDoubleClickTime(view: Int, spaceTime: Int): Boolean {
val time = System.currentTimeMillis()
val timeD = time - lastClickTime
if (timeD < spaceTime && viewId == view) {
return true
}
lastClickTime = time
viewId = view
return false
}

View File

@@ -0,0 +1,10 @@
@file:JvmName("LogUtil")
package com.mogo.chat.util
import com.mogo.chat.aspect.DebugLog
@DebugLog
fun log(tag: String, msg: String) {
}

View File

@@ -0,0 +1,57 @@
package com.mogo.chat.util
import android.content.Context
import android.media.AudioAttributes
import android.media.AudioManager
import android.media.MediaPlayer
import android.os.Build
import com.mogo.chat.constant.TAG
object MediaController {
private var mp: MediaPlayer? = null
fun startPlay(context: Context, audioSources: Int, isLoop: Boolean = false, channel:Int = AudioManager.STREAM_MUSIC) {
if (mp == null) {
mp = MediaPlayer()
}
resetStatus()
val file = context.resources.openRawResourceFd(audioSources)
mp?.apply {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
setAudioStreamType(channel)
} else {
setAudioAttributes(AudioAttributes.Builder().setLegacyStreamType(channel).build())
}
setDataSource(file.fileDescriptor, file.startOffset, file.length)
file.close()
isLooping = isLoop
prepareAsync()
setOnPreparedListener { player ->
log(TAG,"real play 准备播放音频====")
player.start()
}
setOnCompletionListener { player ->
log(TAG,"播放完成====")
player.reset()
}
}
}
fun release() {
log(TAG,"release 释放音频播放====")
if (mp != null) {
resetStatus()
mp!!.release()
mp = null
}
}
private fun resetStatus() {
mp?.apply {
if (isPlaying) {
stop()
}
reset()
}
}
}

View File

@@ -0,0 +1,43 @@
package com.mogo.chat.util
import com.mogo.chat.constant.CALL_TYPE_DEFAULT
import com.mogo.chat.constant.TAG
import com.mogo.chat.model.bean.Sns
object UserInfoHelper {
var userInfo: Sns = Sns()
set(value) {
log(TAG, "个人信息更新:$value")
field = value
}
/**
* 是否是主动匹配
*/
var isInitiativeMatch = false
/**
* 仅为首次进入车聊聊,同步对方信息而创建的临时对象
*/
var tmpSenderInfo: Sns = Sns()
set(value) {
log(TAG, "UserInfoHelper Sender Info update ---> $value")
field = value
}
var currentRoomId = 0
set(value) {
log(TAG, "UserInfoHelper setRoomId ---> $value")
field = value
}
var currentCallType : Int = CALL_TYPE_DEFAULT
set(value) {
log(TAG, "UserInfoHelper setCallType ---> $value")
field = value
}
}

View File

@@ -0,0 +1,20 @@
package com.mogo.chat.util.audio
import com.mogo.chat.util.audio.ChangAnAudioFocusImpl.Companion.changAnAudioFocusImpl
import com.mogo.chat.util.audio.MogoAudioFocusImpl.Companion.mogoAudioFocusImpl
import com.mogo.commons.debug.DebugConfig.*
class AudioFocusImpl {
companion object {
fun getInstance(): IAudioFocus {
return if (getCarMachineType() == CAR_MACHINE_TYPE_SELF_INNOVATE
|| getCarMachineType() == CAR_MACHINE_TYPE_BYD) {
mogoAudioFocusImpl
} else {
changAnAudioFocusImpl
}
}
}
}

View File

@@ -0,0 +1,106 @@
package com.mogo.chat.util.audio;
import android.content.Context;
import android.media.AudioManager;
import com.mogo.chat.callcenter.CallTypeManager;
import com.mogo.chat.callcenter.IMType;
import static com.mogo.chat.util.LogUtil.log;
public class AudioFocusUtil {
private static final String TAG = "AudioFocusUtil";
private MyAudioFocusChangeListener audioListener;
private AudioManager audioManager;
private AudioFocusUtil() {
}
public static class Holder {
private Holder() {
}
private static final AudioFocusUtil instance = new AudioFocusUtil();
}
public static AudioFocusUtil getInstance() {
return Holder.instance;
}
public void init(Context context) {
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
audioListener = new MyAudioFocusChangeListener();
AudioFocusImpl.Companion.getInstance().init(context);
}
public boolean sendGetFocusIntent(Context context) {
return AudioFocusImpl.Companion.getInstance().sendGetFocusIntent(context);
}
public void sendReleaseFocusIntent(Context context) {
AudioFocusImpl.Companion.getInstance().sendReleaseFocusIntent(context);
}
public boolean findMicFocus(Context context) {
return AudioFocusImpl.Companion.getInstance().findMicFocus(context);
}
private int getCurrentPriority(Context context) {
return AudioFocusImpl.Companion.getInstance().getCurrentPriority(context);
}
public void unInit(Context context) {
AudioFocusImpl.Companion.getInstance().unInit(context);
}
private volatile Boolean hasAudioFocus = false;
public void requireDuck() {
log(TAG, "requireDuck===" + hasAudioFocus);
if (!hasAudioFocus) {
hasAudioFocus = true;
try {
audioManager.requestAudioFocus(audioListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void releaseDuck() {
log(TAG, "releaseDuck===" + hasAudioFocus);
if (hasAudioFocus) {
hasAudioFocus = false;
try {
audioManager.abandonAudioFocus(audioListener);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private class MyAudioFocusChangeListener implements AudioManager.OnAudioFocusChangeListener {
@Override
public void onAudioFocusChange(int focusChange) {
log(TAG, "onAudioFocusChange: " + focusChange);
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
hasAudioFocus = true;
if (CallTypeManager.Companion.getCallTypeManager().getCallStatus() == IMType.INIT_CALL) {
AudioFocusUtil.getInstance().releaseDuck();
}
break;
case AudioManager.AUDIOFOCUS_LOSS:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
hasAudioFocus = false;
break;
}
}
}
}

View File

@@ -0,0 +1,41 @@
package com.mogo.chat.util.audio
import android.content.Context
import com.fce.micro.MicManager
import com.fce.micro.callback.MicroDef
import com.mogo.chat.constant.TAG
import com.mogo.chat.util.log
class ChangAnAudioFocusImpl private constructor() : IAudioFocus {
companion object {
val changAnAudioFocusImpl by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
ChangAnAudioFocusImpl()
}
}
override fun init(context:Context) {
MicManager.getInstance().initMicParam(context, MicroDef.MIC_DEBUNK)
MicManager.getInstance().setMicReleaseBack {
//收到该回调表示有更高优先级应用使用mic停止录音释放mic
sendReleaseFocusIntent(context)
}
MicManager.getInstance().setMicObtainBack {
//APP收到此回调时开始录音
log(TAG,"ChangAnAudioFocusImpl MicObtainBack : 可以开始录音了")
}
}
override fun sendGetFocusIntent(context: Context) :Boolean{
return MicManager.getInstance().requestMicSrc()
}
override fun sendReleaseFocusIntent(context: Context) {
MicManager.getInstance().releaseMicSrc()
}
override fun unInit(context: Context) {
MicManager.getInstance().releaseMicSrc()
}
}

View File

@@ -0,0 +1,35 @@
package com.mogo.chat.util.audio
import android.content.Context
interface IAudioFocus {
fun init(context: Context)
/**
* 查询麦克风焦点
* 麦克风优先级
* true,代表当前麦克风焦点在你这
*/
fun findMicFocus(context: Context): Boolean {
return false
}
/**
* 查询当前的麦克风使用的优先级
*
* @return 麦克风优先级
*/
fun getCurrentPriority(context: Context): Int {
return 0
}
/**
* 申请麦克风焦点
*/
fun sendGetFocusIntent(context: Context):Boolean
fun sendReleaseFocusIntent(context: Context)
fun unInit(context: Context)
}

View File

@@ -0,0 +1,93 @@
package com.mogo.chat.util.audio
import android.content.Context
import com.mogo.chat.constant.TAG
import com.mogo.chat.util.log
import com.zhidao.auto.micstrategy.MicStrategyManager
import com.zhidao.auto.micstrategy.MicStrategyManager.MicFocusListener
import com.zhidao.auto.micstrategy.MicStrategyManagerImpl
class MogoAudioFocusImpl private constructor() : IAudioFocus {
private var listener: MyMicFocusListener? = null
companion object {
val mogoAudioFocusImpl by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
MogoAudioFocusImpl()
}
}
override fun init(context: Context) {
listener = MyMicFocusListener()
try {
if (listener == null) listener = MyMicFocusListener()
MicStrategyManagerImpl.getInstance(context).addMicFocusListener(listener)
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun findMicFocus(context: Context): Boolean {
super.findMicFocus(context)
var can = false
try {
can = MicStrategyManagerImpl.getInstance(context).findMicFocus(MicStrategyManager.VOIP_PRIORITY)
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
return can
}
override fun getCurrentPriority(context: Context): Int {
return try {
MicStrategyManagerImpl.getInstance(context).currentPriority
} catch (e: java.lang.Exception) {
e.printStackTrace()
0
}
}
override fun sendGetFocusIntent(context: Context):Boolean {
return try {
if (listener == null) listener = MyMicFocusListener()
MicStrategyManagerImpl.getInstance(context).requestMicFocus(MicStrategyManager.VOIP_PRIORITY, listener)
log(TAG, "sendGetFocusIntent: ")
true
} catch (e: java.lang.Exception) {
e.printStackTrace()
false
}
}
override fun sendReleaseFocusIntent(context: Context) {
try {
if (listener == null) listener = MyMicFocusListener()
MicStrategyManagerImpl.getInstance(context).abandonMicFocus()
log(TAG, "sendReleaseFocusIntent: ")
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
override fun unInit(context: Context) {
try {
if (listener != null) MicStrategyManagerImpl.getInstance(context).removeMicFocusListener(listener)
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
class MyMicFocusListener : MicFocusListener {
/**
* 麦克风焦点状态
*
* @param i
*/
override fun onMicFocuschanged(i: Int) {
//do nothing
}
}
}

View File

@@ -0,0 +1,19 @@
package com.mogo.chat.util.sp
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import com.mogo.commons.AbsMogoApplication
fun getSP(fileName: String): SharedPreferences {
return AbsMogoApplication.getApp().applicationContext.getSharedPreferences(fileName, Context.MODE_PRIVATE)
}
inline fun getCommitSP(fileName: String, action: SharedPreferences.Editor.() -> Unit) {
getSP(fileName).edit(commit = true, action = action)
}
inline fun getApplySp(fileName: String, action: SharedPreferences.Editor.() -> Unit) {
getSP(fileName).edit(commit = false, action = action)
}

View File

@@ -0,0 +1,187 @@
@file:JvmName("SharedPreferenceUtil")
package com.mogo.chat.util.sp
import com.mogo.chat.aspect.DebugLog
const val TEMPORARY_FILE_NAME = "temporary_im_data"
const val CONFIG_FILE_NAME = "configs_im_data"
const val FILE_NAME = "settings_im_data"
const val PARAM_ROOM_ID = "PARAM_ROOM_ID"
const val PARAM_FRIEND_LIST_CALL = "PARAM_FRIEND_LIST_CALL"
const val PARAM_NEW_FOCUS = "PARAM_NEW_FOCUS"
const val PARAM_VOICE_TYPE = "PARAM_VOICE_TYPE"
const val PARAM_CALL_TIME = "PARAM_CALL_TIME"
const val PARAM_INIT_TIP = "PARAM_INIT_TIP"
const val PARAM_CAR_ONLINE_STATUS = "PARAM_CAR_ONLINE_STATUS"
const val PARAM_GUIDE_SHOW_STATUS = "PARAM_GUIDE_SHOW_STATUS"
const val PARAM_CONFIG_EXPIRY_TIME = "PARAM_CONFIG_EXPIRY_TIME"
const val PARAM_CONFIG_COUNT_DOWN_TIME = "PARAM_CONFIG_COUNT_DOWN_TIME"
const val PARAM_CONFIG_VOICE_CONTENT = "PARAM_CONFIG_VOICE_CONTENT"
const val PARAM_CONFIG_IMAGE_IS_SAVED = "PARAM_CONFIG_IMAGE_IS_SAVED"
const val PARAM_CONFIG_TOPIC_GUIDE = "PARAM_CONFIG_TOPIC_GUIDE"
const val PARAM_CONFIG_FOCUS_NOTICE_TIMES = "PARAM_CONFIG_FOCUS_NOTICE_TIMES"
const val PARAM_CONFIG_OWN_NICK_NAME = "PARAM_CONFIG_OWN_NICK_NAME"
const val PARAM_CONFIG_OWN_HEAD_IMG = "PARAM_CONFIG_OWN_HEAD_IMG"
fun saveRoomId(roomId: Int) {
getCommitSP(TEMPORARY_FILE_NAME) {
putInt(PARAM_ROOM_ID, roomId)
}
}
fun hasRoomId(): Boolean {
return getSP(TEMPORARY_FILE_NAME).getInt(PARAM_ROOM_ID, 0) != 0
}
fun getRoomId(): Int {
return getSP(TEMPORARY_FILE_NAME).getInt(PARAM_ROOM_ID, 0)
}
fun setCallFromFriendList(call: Boolean) {
getCommitSP(TEMPORARY_FILE_NAME) {
putBoolean(PARAM_FRIEND_LIST_CALL, call)
}
}
fun hasCallFromFriendList(): Boolean {
return getSP(TEMPORARY_FILE_NAME).getBoolean(PARAM_FRIEND_LIST_CALL, false)
}
fun hasFocus(): Boolean {
return getSP(TEMPORARY_FILE_NAME).getBoolean(PARAM_NEW_FOCUS, false)
}
fun newFocus(focus: Boolean) {
getApplySp(TEMPORARY_FILE_NAME) {
putBoolean(PARAM_NEW_FOCUS, focus)
}
}
fun setVoiceType(voiceType: Int) {
getApplySp(FILE_NAME) {
putInt(PARAM_VOICE_TYPE, voiceType)
}
}
fun getVoiceType(): Int {
return getSP(FILE_NAME).getInt(PARAM_VOICE_TYPE, 0)
}
fun setCarOnLineStatus(onLine: Boolean) {
getApplySp(FILE_NAME) {
putBoolean(PARAM_CAR_ONLINE_STATUS, onLine)
}
}
/**
* 本地缓存的在线隐身状态
*/
fun getCarOnLineStatus(): Boolean {
return getSP(FILE_NAME).getBoolean(PARAM_CAR_ONLINE_STATUS, true)
}
fun initTip(initType: Int) {
getApplySp(FILE_NAME) {
putBoolean(PARAM_INIT_TIP + initType, true)
}
}
fun getInitStatus(initType: Int): Boolean {
return getSP(FILE_NAME).getBoolean(PARAM_INIT_TIP + initType, false)
}
fun recordCallTime() {
getApplySp(FILE_NAME) {
putLong(PARAM_CALL_TIME, System.currentTimeMillis())
}
}
fun getTalkTime(): Long {
val startCallTime = getSP(FILE_NAME).getLong(PARAM_CALL_TIME, 0)
return if (startCallTime.toString() == "0") {
0
} else {
System.currentTimeMillis() - startCallTime
}
}
fun guideHasShown() {
getApplySp(FILE_NAME) {
putBoolean(PARAM_GUIDE_SHOW_STATUS, true).apply()
}
}
fun getGuideShowStatus(): Boolean {
return getSP(FILE_NAME).getBoolean(PARAM_GUIDE_SHOW_STATUS, false)
}
/**********************************************配置Data*****************************************************/
fun setExpiryTime(expiryTime: Long) {
getApplySp(CONFIG_FILE_NAME) {
putLong(PARAM_CONFIG_EXPIRY_TIME, expiryTime)
}
}
fun isExpiryTime(requestTime: Long): Boolean {
return getSP(CONFIG_FILE_NAME).getLong(PARAM_CONFIG_EXPIRY_TIME, 0) != requestTime
}
fun setCountDownTime(countDownTime: Int) {
getApplySp(CONFIG_FILE_NAME) {
putInt(PARAM_CONFIG_COUNT_DOWN_TIME, countDownTime)
}
}
fun getCountDownTime(): Int {
return getSP(CONFIG_FILE_NAME).getInt(PARAM_CONFIG_COUNT_DOWN_TIME, 0)
}
fun setConfigVoiceContent(voiceContent: String) {
getApplySp(CONFIG_FILE_NAME) {
putString(PARAM_CONFIG_VOICE_CONTENT, voiceContent)
}
}
fun getConfigVoiceContent(): String {
return getSP(CONFIG_FILE_NAME).getString(PARAM_CONFIG_VOICE_CONTENT, "")!!
}
fun setImageSaveStatus(saveStatus: Boolean) {
getApplySp(CONFIG_FILE_NAME) {
putBoolean(PARAM_CONFIG_IMAGE_IS_SAVED, saveStatus)
}
}
fun getImageSaveStatus(): Boolean {
return getSP(CONFIG_FILE_NAME).getBoolean(PARAM_CONFIG_IMAGE_IS_SAVED, false)
}
fun setFocusNoticeTimes(times: Int) {
getApplySp(CONFIG_FILE_NAME) {
putInt(PARAM_CONFIG_FOCUS_NOTICE_TIMES, times)
}
}
fun getFocusNoticeTimes(): Int {
return getSP(CONFIG_FILE_NAME).getInt(PARAM_CONFIG_FOCUS_NOTICE_TIMES, 0)
}
@DebugLog
fun setTopicGuideContent(content: String) {
getApplySp(CONFIG_FILE_NAME) {
putString(PARAM_CONFIG_TOPIC_GUIDE, content)
}
}
fun getTopicGuideContent(): Array<String> {
val content = getSP(CONFIG_FILE_NAME).getString(PARAM_CONFIG_TOPIC_GUIDE, "")
return if (content.isNullOrEmpty()) emptyArray() else content.split("/").toTypedArray()
}