Commit a9a7a92e by 严久程

课程模块、支付模块

parent 1e8f36a5
......@@ -75,6 +75,7 @@ dependencies {
api project(":ydl-webview")
api project(":ydl-platform")
api project(":ydl-media")
api project(":ydl-pay")
} else {
//发布时使用
compileOnly rootProject.ext.dependencies["ydl-m-user-api"]
......
......@@ -12,7 +12,6 @@ import butterknife.BindView;
import butterknife.ButterKnife;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.ydl.ydlcommon.base.BaseActivity;
import com.yidianling.course.courseNew.home.CourseHomeFragment;
import com.yidianling.course.courseNew.mine.MyCourseActivity;
import com.yidianling.course.router.CourseIn;
import com.yidianling.course.widget.SearchBarView;
......@@ -25,8 +24,6 @@ public class CourseActivity extends BaseActivity {
@BindView(R2.id.content)
FrameLayout content;
@BindView(R2.id.img_music)
ImageView imgMusic;
@BindView(R2.id.iv_back)
ImageView ivBack;
@BindView(R2.id.tv_left_menu)
......@@ -79,15 +76,6 @@ public class CourseActivity extends BaseActivity {
finish();
}
});
imgMusic.setOnClickListener(v -> {
if (YDLMusicHelper.INSTANCE.isCoursePlaying()) {
//课程播放页
YDLMusicHelper.INSTANCE.startCoursePlayActivity(getMContext(), 1, 0, "", false);
} else {
imgMusic.setVisibility(View.GONE);
}
});
leftMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
......@@ -104,23 +92,19 @@ public class CourseActivity extends BaseActivity {
* 初始化tab
*/
private void initTags() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.content);
if (fragment == null) {
fragment = new CourseHomeFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.content, fragment)
.commit();
}
//todo 引用flutter的课程频道页面
// Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.content);
// if (fragment == null) {
// fragment = new CourseHomeFragment();
// getSupportFragmentManager().beginTransaction()
// .add(R.id.content, fragment)
// .commit();
// }
}
@Override
protected void onResume() {
super.onResume();
if (YDLMusicHelper.INSTANCE.isCoursePlaying()) {
imgMusic.setVisibility(View.VISIBLE);
} else {
imgMusic.setVisibility(View.GONE);
}
}
public void disPro() {
......
......@@ -80,12 +80,7 @@ public class CourseListItemView extends ConstraintLayout implements View.OnClick
}
tvCourseItemComment.setOnClickListener(v -> CourseCommentActivity.Companion.startActivity((Activity) context, mCourse.id + ""));
tvCourseItemFirst.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
YDLRouterManager.Companion.router(mCourse.chatLinkUri);
}
});
tvCourseItemFirst.setOnClickListener(v -> YDLRouterManager.Companion.router(mCourse.chatLinkUri));
}
@Override
......
......@@ -24,10 +24,12 @@ import com.ydl.media.audio.utils.PlayProgressUtil
import com.ydl.media.view.PlayTypeEnum
import com.ydl.media.view.PlayerFloatHelper
import com.ydl.ydl_image.module.GlideApp
import com.ydl.ydl_pay.CommonPayDialog
import com.ydl.ydl_router.manager.YDLRouterManager
import com.ydl.ydlcommon.adapter.CommonRecyclerAdapter
import com.ydl.ydlcommon.base.BaseActivity
import com.ydl.ydlcommon.bean.ShareData
import com.ydl.ydlcommon.data.PlatformDataManager
import com.ydl.ydlcommon.router.IYDLRouterConstant
import com.ydl.ydlcommon.router.YdlCommonRouterManager
import com.ydl.ydlcommon.utils.ScreenUtil
......@@ -39,6 +41,7 @@ import com.ydl.ydlcommon.view.dialog.YDLShareDialog
import com.yidianling.common.tools.RxImageTool
import com.yidianling.common.tools.RxNetTool
import com.yidianling.common.tools.ToastUtil
import com.yidianling.course.BuildConfig
import com.yidianling.course.R
import com.yidianling.course.bean.CourseMediaBean
import com.yidianling.course.bean.CourseMediaDetailBean
......@@ -497,7 +500,7 @@ class CoursePlayActivity : BaseActivity() {
.setCourseId(course_id.toString())
.setToken(userInfo.token)
.setUid(userInfo.userId)
.setFfrom(YdlDataManager.getRam().getChannelName())
.setFfrom(PlatformDataManager.getRam().getChannelName())
.setListener(object : CommonPayDialog.OnPayResultListener {
override fun onSuccesed() {
//刷新界面
......
......@@ -4,18 +4,15 @@ import android.annotation.SuppressLint
import android.text.TextUtils
import android.view.ViewGroup
import android.widget.RelativeLayout
import com.ydl.media.audio.AudioPlayer
import com.ydl.media.audio.model.Music
import com.ydl.ydlcommon.view.dialog.CommonDialog
import com.yidianling.common.tools.RxDeviceTool
import com.yidianling.common.tools.RxNetTool
import com.yidianling.course.bean.CourseExtraBean
import com.yidianling.course.bean.CourseMediaBean
import com.yidianling.course.listener.HPlayStatusListener
import com.yidianling.course.widget.HPlayView
import com.yidianling.ydlcommon.bean.CourseExtraBean
import com.yidianling.ydlcommon.bean.CourseMediaBean
import com.yidianling.ydlcommon.dialog.CommonDialog
import com.yidianling.ydlcommon.player.MusicInfoBean
import com.yidianling.ydlcommon.player.YDLMusicHelper
import com.yidianling.ydlcommon.player.player.HPlayStatusListener
import com.yidianling.ydlcommon.player.view.HPlayView
/**
......@@ -69,12 +66,8 @@ class CoursePlayItemViewAudio : RelativeLayout, PlayViewInterface {
//设置监听事件
fun setListener() {
playView?.listener = object : HPlayStatusListener {
override fun isCanPlay(data: MusicInfoBean?): Boolean {
override fun isCanPlay(data: Music?): Boolean {
var canPlay = false
//判断当前课程是否试听
if (data?.isTestPlay == true) {
canPlay = true
} else {
//非试听
if (courseExtra!!.isBuy) {
//已购买
......@@ -95,11 +88,10 @@ class CoursePlayItemViewAudio : RelativeLayout, PlayViewInterface {
.setCancelAble(false)
.show()
}
}
return canPlay
}
override fun onPrepared(data: MusicInfoBean?, index: Int) {
override fun onPrepared(data: Music?, index: Int) {
//更新播放列表的状态
activity!!.updatePlayingListStatus(index)
}
......@@ -118,7 +110,7 @@ class CoursePlayItemViewAudio : RelativeLayout, PlayViewInterface {
this.courseExtra = courseExtra
currentIndex = index
YDLMusicHelper.course_id = courseExtra.id.toInt()
// YDLMusicHelper.course_id = courseExtra.id.toInt()
if (courseExtra.isBuy) {
playView?.setAutoNext(true)
......@@ -131,12 +123,12 @@ class CoursePlayItemViewAudio : RelativeLayout, PlayViewInterface {
playView!!.setData(stringToMusicPlayerList(playList))
if (playView?.control?.isPlaying() == true) {
if (AudioPlayer.get().isPlaying) {
hasEnsureNetStatus = true
}
if (RxNetTool.isWifi(activity!!)) {
if (playView?.control?.isPlaying() == true && (from == 1 || from == 2)) {
if (AudioPlayer.get().isPlaying && (from == 1 || from == 2)) {
if (TextUtils.equals(playView?.getCurrentUrl(), list[currentIndex].url)) {
playView?.updateView(currentIndex)
} else {
......@@ -147,7 +139,7 @@ class CoursePlayItemViewAudio : RelativeLayout, PlayViewInterface {
}
} else {
if (hasEnsureNetStatus) {
if (playView?.control?.isPlaying() == true && (from == 1 || from == 2)) {
if (AudioPlayer.get().isPlaying && (from == 1 || from == 2)) {
if (TextUtils.equals(playView?.getCurrentUrl(), list[currentIndex].url)) {
playView?.updateView(currentIndex)
} else {
......@@ -159,7 +151,7 @@ class CoursePlayItemViewAudio : RelativeLayout, PlayViewInterface {
} else {
playView?.showNetNotice {
hasEnsureNetStatus = true
if (playView?.control?.isPlaying() == true && (from == 1 || from == 2)) {
if (AudioPlayer.get().isPlaying && (from == 1 || from == 2)) {
if (TextUtils.equals(playView?.getCurrentUrl(), list[currentIndex].url)) {
playView?.updateView(currentIndex)
} else {
......@@ -174,15 +166,15 @@ class CoursePlayItemViewAudio : RelativeLayout, PlayViewInterface {
}
//将列表转为播放器可用列表
private fun stringToMusicPlayerList(list: List<CourseMediaBean>): ArrayList<MusicInfoBean> {
var nlist = ArrayList<MusicInfoBean>()
private fun stringToMusicPlayerList(list: List<CourseMediaBean>): ArrayList<Music> {
var nlist = ArrayList<Music>()
try {
for (i in list.indices) {
var be = MusicInfoBean()
be.url = list[i].url
be.pic = courseExtra!!.pic
be.isTestPlay = !courseExtra!!.isBuy
var be = Music()
be.path = list[i].url
be.coverPath = courseExtra!!.pic
be.title = list[i].title
be.artist = list[i].doctorName
nlist.add(be)
}
} catch (e: Exception) {
......@@ -193,10 +185,10 @@ class CoursePlayItemViewAudio : RelativeLayout, PlayViewInterface {
override fun onDestroy() {
//释放播放器
if (playView?.control?.isPlaying() != true) {
if (AudioPlayer.get().isPlaying) {
playView?.onDestroy()
playView = null
YDLMusicHelper.stop()
AudioPlayer.get().stopPlayer()
} else {
playView?.onDestroy()
playView = null
......
......@@ -57,10 +57,10 @@ class CourseSearchAdapterWrapper(
var view:View? = null
return when (viewType) {
TYPE_FOOTER_LOADING -> {
FooterHolder(mInflater!!.inflate(R.layout.footer, parent, false), TYPE_FOOTER_LOADING)
FooterHolder(mInflater!!.inflate(R.layout.course_footer, parent, false), TYPE_FOOTER_LOADING)
}
TYPE_FOOTER_NOMORE -> {
FooterHolder(mInflater!!.inflate(R.layout.footer, parent, false), TYPE_FOOTER_NOMORE)
FooterHolder(mInflater!!.inflate(R.layout.course_footer, parent, false), TYPE_FOOTER_NOMORE)
}
else -> {
mAdapter.onCreateViewHolder(parent, viewType)
......
package com.yidianling.course.listener
import com.ydl.media.audio.model.Music
/**
* 播放状态监听起
* Created by hgw on 2018/4/28.
*/
interface HPlayStatusListener{
//判断是否可以播放
fun isCanPlay(data : Music?):Boolean
//音频初始化完成
fun onPrepared(data : Music?, index:Int=0)
}
\ No newline at end of file
package com.yidianling.course.router
import android.app.Activity
import android.content.Intent
import com.alibaba.android.arouter.launcher.ARouter
import com.ydl.media.audio.AudioPlayer
import com.yidianling.course.courseNew.CourseTopicActivity
import com.yidianling.router.course.ICourseRouter
import com.yidianling.ydlcommon.player.YDLMusicHelper
/**
* Created by hgw on 2018/5/3.
......@@ -11,25 +13,30 @@ import com.yidianling.ydlcommon.player.YDLMusicHelper
class CourseRouterImp : ICourseRouter{
override fun closePlayer() {
if (YDLMusicHelper.isCoursePlaying()) {
YDLMusicHelper.stop()
if (AudioPlayer.get().isPlaying) {
AudioPlayer.get().stopPlayer()
}
}
override fun isPlaying(): Boolean {
return YDLMusicHelper.isPlaying()
return AudioPlayer.get().isPlaying
}
override fun play(){
YDLMusicHelper.replay()
AudioPlayer.get().play()
}
override fun pause(){
YDLMusicHelper.pause()
AudioPlayer.get().playPause()
}
override fun startCoursePlayPage(activity: Activity, from: Int) {
YDLMusicHelper.startCoursePlayActivity(activity,from)
ARouter.getInstance()
.build("/course/play")
.withInt("from", from)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.withBoolean("isFromFloatView", false)
.navigation()
}
override fun courseTopic(activity: Activity, id: String){
......
......@@ -11,7 +11,7 @@ import android.widget.LinearLayout
import com.yidianling.common.tools.RxImageTool
import com.yidianling.course.R
import com.yidianling.course.bean.CourseCouponBean
import kotlinx.android.synthetic.main.view_course_coupon_detail.view.*
import kotlinx.android.synthetic.main.course_view_course_coupon_detail.view.*
import java.lang.Float
import java.math.BigDecimal
......@@ -33,8 +33,8 @@ class CourseCouponDetailView : LinearLayout {
val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, RxImageTool.dp2px(90f))
params.bottomMargin = RxImageTool.dp2px(10f)
layoutParams = params
setBackgroundResource(R.drawable.img_course_coupon_detail_bg)
View.inflate(context, R.layout.view_course_coupon_detail, this)
setBackgroundResource(R.drawable.course_img_course_coupon_detail_bg)
View.inflate(context, R.layout.course_view_course_coupon_detail, this)
}
......
......@@ -11,10 +11,9 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestOptions
import com.ydl.ydl_image.module.GlideApp
import com.ydl.ydl_image.transform.GlideRoundTopTransform
import com.yidianling.common.tools.RxImageTool
import com.yidianling.course.R
import com.yidianling.course.bean.PostersShareBean
import kotlinx.android.synthetic.main.view_course_poster_template.view.*
import kotlinx.android.synthetic.main.course_view_course_poster_template.view.*
import java.util.concurrent.Executors
......@@ -37,7 +36,7 @@ class CoursePosterTemplate(var mContext: Activity) : CardView(mContext) {
*/
private fun initView() {
// radius = RxImageTool.dp2px(10f).toFloat()
View.inflate(context, R.layout.view_course_poster_template, this)
View.inflate(context, R.layout.course_view_course_poster_template, this)
}
@SuppressLint("SetTextI18n")
......@@ -93,7 +92,7 @@ class CoursePosterTemplate(var mContext: Activity) : CardView(mContext) {
}
private fun setType(isDefault: Boolean) {
root_layout.setBackgroundResource(if (isDefault) R.drawable.poster_one else R.drawable.poster_two)
root_layout.setBackgroundResource(if (isDefault) R.drawable.course_poster_one else R.drawable.course_poster_two)
view_line.isEnabled = isDefault
iv_poster_one.isEnabled = isDefault
iv_poster_two.isEnabled = isDefault
......
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true">
<shape>
<corners android:radius="21dp"/>
<gradient android:endColor="@color/color_FAD642" android:startColor="@color/color_FA5729" />
</shape>
</item>
</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:state_enabled="true">
<shape>
<corners android:radius="11dp"/>
<gradient
android:angle="180"
android:endColor="@color/color_FFC000" android:startColor="@color/color_FF8C00" />
</shape>
</item>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="270"
android:endColor="@color/white"
android:startColor="#00FFFFFF" />
</shape>
\ 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:state_enabled="true">
<shape android:shape="oval">
<solid android:color="@color/color_0D1A30" />
<size android:width="15dp" android:height="15dp" />
</shape>
</item>
<item android:state_enabled="false">
<shape android:shape="oval">
<solid android:color="@color/color_FDD33D" />
<size android:width="15dp" android:height="15dp" />
</shape>
</item>
</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:state_enabled="true">
<shape>
<solid android:color="@color/white" />
<corners android:radius="10dp" />
</shape>
</item>
</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:state_enabled="true">
<shape android:shape="line">
<stroke android:width="2px" android:color="@color/color_0D1A30" android:dashWidth="15px" android:dashGap="20px" />
<size android:height="1dp" />
</shape>
</item>
<item android:state_enabled="false">
<shape android:shape="line">
<stroke android:width="2px" android:color="@color/color_FDD33D" android:dashWidth="15px" android:dashGap="20px" />
<size android:height="1dp" />
</shape>
</item>
</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:state_enabled="true">
<shape>
<corners android:radius="2dp" />
<solid android:color="@color/white" />
<stroke android:width="0.5dp" android:color="@color/color_BFBFBF" />
</shape>
</item>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="7dp" />
<solid android:color="@color/main_theme" />
<stroke
android:width="1dp"
android:color="@color/main_theme" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="45dp"
android:orientation="horizontal"
android:background="@color/color_50FFFFFF"
android:gravity="center">
<TextView
android:id="@+id/footer_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center">
<TextView
android:id="@+id/tv_price"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:lineSpacingExtra="0dp"
android:textColor="@color/color_FF9100"
android:textSize="26sp"
android:textStyle="bold"
tools:text="50" />
<TextView
android:id="@+id/tv_discountCont"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_price"
android:gravity="center_horizontal"
android:lineSpacingExtra="0dp"
android:textColor="@color/color_FF9100"
android:textSize="10sp"
tools:text="满500元可用" />
</RelativeLayout>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="5"
android:paddingLeft="16dp"
android:paddingRight="2dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginTop="17dp"
android:layout_marginRight="10dp"
android:layout_toLeftOf="@+id/tv_use"
android:ellipsize="end"
android:maxLength="20"
android:maxLines="1"
android:textColor="@color/color_242424"
android:textSize="15sp"
tools:text="咨询优惠券" />
<TextView
android:id="@+id/tv_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_title"
android:layout_marginTop="1dp"
android:text="有效期至2018-08-31"
android:textColor="@color/color_242424"
android:textSize="11sp" />
<TextView
android:id="@+id/tv_use"
android:layout_width="wrap_content"
android:layout_height="22dp"
android:layout_alignParentRight="true"
android:layout_marginTop="16dp"
android:layout_marginRight="12dp"
android:background="@drawable/course_background_course_coupon_detail_use"
android:gravity="center"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="使用"
android:textColor="@color/white"
android:textSize="12sp"
android:visibility="gone"
tools:visibility="visible" />
<TextView
android:id="@+id/tv_use_condition"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginTop="1dp"
android:layout_marginBottom="14dp"
android:text="指定课程使用"
android:textColor="@color/color_666666"
android:textSize="11sp" />
</RelativeLayout>
</merge>
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00000000"
android:gravity="center"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:id="@+id/card_view"
android:layout_width="310dp"
android:layout_height="397dp"
android:layout_marginLeft="33dp"
android:layout_marginRight="32dp"
android:background="@color/color_FFFFFF"
app:cardCornerRadius="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="28dp"
android:textColor="@color/color_242424"
android:textSize="20sp"
tools:text="领取成功" />
<TextView
android:id="@+id/tv_introduction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="未领到的优惠券已经被抢光了"
android:textColor="@color/color_666666"
android:textSize="12sp"
android:visibility="gone" />
<ImageView
android:id="@+id/iv_empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_weight="1"
android:scaleType="center"
android:src="@drawable/course_img_course_background"
android:visibility="gone" />
<ScrollView
android:id="@+id/scrollview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_weight="1"
android:scrollbars="none">
<LinearLayout
android:id="@+id/ll_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:orientation="vertical" />
</ScrollView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="82dp"
android:layout_marginBottom="30dp"
android:background="@drawable/course_background_course_coupon_layer">
<TextView
android:id="@+id/tv_ensure"
android:layout_width="match_parent"
android:layout_height="42dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginLeft="45dp"
android:layout_marginRight="45dp"
android:background="@drawable/course_background_coupon_button"
android:gravity="center"
android:textColor="@color/white"
android:textSize="15sp"
tools:text="立即领取" />
</RelativeLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
<ImageView
android:id="@+id/iv_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="37dp"
android:padding="10dp"
android:src="@drawable/course_dialog_pop_close" />
</LinearLayout>
\ No newline at end of file
......@@ -130,4 +130,11 @@
<color name="color_66000000">#66000000</color>
<color name="color_FFFFFF">#FFFFFF</color>
<color name="color_ACACAC">#ACACAC</color>
<color name="color_50FFFFFF">#B3FFFFFF</color>
<color name="color_FF9100">#FF9100</color>
<color name="color_FFC000">#FFC000</color>
<color name="color_FF8C00">#FF8C00</color>
<color name="color_0D1A30">#0D1A30</color>
<color name="color_FDD33D">#FDD33D</color>
<color name="color_BFBFBF">#BFBFBF</color>
</resources>
\ No newline at end of file
include ':app',":router", ":m-course", ':ydl-net', ':ydl-utils', ':ydl-platform', ':ydl-webview', ':ydl-media',":m-user", ':m-consultant', ':m-muse', ':m-fm', ':m-tests'
\ No newline at end of file
include ':app',":router", ":m-course", ':ydl-net', ':ydl-utils', ':ydl-platform', ':ydl-webview', ':ydl-media',":m-user", ':m-consultant', ':m-muse', ':m-fm', ':m-tests', ':ydl-pay'
\ No newline at end of file
......@@ -24,13 +24,41 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
api fileTree(dir: 'libs', include: ['*.jar','*.aar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0'
implementation 'com.facebook.stetho:stetho:1.5.0'
implementation 'com.facebook.stetho:stetho-okhttp3:1.4.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'de.greenrobot:eventbus:2.4.0'
api 'com.umeng.sdk:share-wechat:6.9.1'
}
repositories {
flatDir {
dirs 'libs'
}
mavenCentral()
}
\ No newline at end of file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yidianling.ydl_pay"/>
package="com.yidianling.ydl_pay">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
</manifest>
package com.ydl.ydl_pay.actionpoint
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkInfo
import com.ydl.ydl_pay.http.HttpUtils
import com.ydl.ydl_pay.http.utils.RxDeviceTool
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
/**
* 行为数据埋点工具类
* Created by xj on 2019/6/22.
*/
internal class ActionCountUtils {
companion object {
const val TAG: String = "ActionCountUtils"
/**
* 基础行为数据埋点调用的方法
*/
fun count(uid: String?, partId: String, position: String, url: String, api: String, sign1: String) {
try {
val actionDataParams = ActionDataBean.Builder()
actionDataParams.partId(partId)
actionDataParams.position(position)
actionDataParams.url(url)
uid?.let {
actionDataParams.uid(uid)
}
actionDataParams.time(System.currentTimeMillis())
actionDataParams.appVersion(RxDeviceTool.getAppVersionName(RxDeviceTool.getContext()))
actionDataParams.appId(BIConstants.APP_ID)
actionDataParams.api(api)
actionDataParams.manufacturer(android.os.Build.BRAND.trim().toUpperCase())
actionDataParams.model(android.os.Build.MODEL)
actionDataParams.os(BIConstants.OS)
actionDataParams.osVersion(android.os.Build.VERSION.RELEASE)
actionDataParams.wifi(if (isWifi()) 0 else 1)
actionDataParams.sign1(sign1)
actionDataParams.screenWidth(RxDeviceTool.getScreenWidth(RxDeviceTool.getContext()))
actionDataParams.screenHeight(RxDeviceTool.getScreenHeight(RxDeviceTool.getContext()))
//剩余额外参数根据需求定义
//请求
request(actionDataParams.build())
} catch (e: Exception) {
}
}
/**
* 传入ActionDataParams参数,访问接口
*/
fun request(actionDataBean: ActionDataBean) {
try {
HttpUtils.actionDataCount(actionDataBean)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
}) {
}
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 判断是否是wifi
*/
private fun isWifi(): Boolean {
try {
var connectivityManager: ConnectivityManager = RxDeviceTool.getContext().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
var info: NetworkInfo = connectivityManager.activeNetworkInfo
if (info != null && info.type == ConnectivityManager.TYPE_WIFI) {
return true
}
return false
} catch (e: Exception) {
return false
}
}
}
}
\ No newline at end of file
package com.ydl.ydl_pay.actionpoint
/**
* Created by xj on 2019/6/22.
*/
internal class ActionDataBean private constructor(builder: Builder) {
/**
* partId : sy_1 //埋点板块
* position : psychic_advisory_click //点击事件
* uid : 123 //用户ID
* time : 1560389634000 //事件发生时间,毫秒级时间戳
* ip : 192.168.0.1 //IP地址
* appVersion : 3.8.00 //版本号
* appId : ydl-app-android-user
* url : https://www.baidu.com //访问地址
* server : 123
* api : https://www.baidu.com/api
* manufacturer : Apple //设备厂商,字符串类型,如"Apple"
* model : iphone6 //设备型号,字符串类型,如"iphone6"
* os : iOS //操作系统,字符串类型,如"iOS"
* osVersion : 8.1.1 //操作系统版本,字符串类型,如"8.1.1"
* screenHeight : 1920 //屏幕高度,数字类型,如1920
* screenWidth : 1080 //屏幕宽度,数字类型,如1080
* wifi : 0 是否 WIFI,byte类型,如0(是),1(否)
* sign1 :
* sign2 :
* sign3 :
* sign4 :
* sign5 :
*/
var partId: String? = null
var position: String? = null
var uid: String? = null
var time: Long = 0.toLong()
var ip: String? = null
var appVersion: String? = null
var appId: String? = null
var url: String? = null
var server: String? = null
var api: String? = null
var manufacturer: String? = null
var model: String? = null
var os: String? = null
var osVersion: String? = null
var screenHeight: Int = 0
var screenWidth: Int = 0
var wifi: Int = 0
var sign1: String? = null
var sign2: String? = null
var sign3: String? = null
var sign4: String? = null
var sign5: String? = null
init {
this.partId = builder.partId
this.position = builder.position
this.uid = builder.uid
this.time = builder.time
this.ip = builder.ip
this.appVersion = builder.appVersion
this.appId = builder.appId
this.url = builder.url
this.server = builder.server
this.api = builder.api
this.manufacturer = builder.manufacturer
this.model = builder.model
this.os = builder.os
this.osVersion = builder.osVersion
this.screenHeight = builder.screenHeight
this.screenWidth = builder.screenWidth
this.wifi = builder.wifi
this.sign1 = builder.sign1
this.sign2 = builder.sign2
this.sign3 = builder.sign3
this.sign4 = builder.sign4
this.sign5 = builder.sign5
}
class Builder {
internal var partId: String? = ""
internal var position: String? = ""
internal var uid: String? = ""
internal var time: Long = 0.toLong()
internal var ip: String? = ""
internal var appVersion: String? = ""
internal var appId: String? = ""
internal var url: String? = ""
internal var server: String? = ""
internal var api: String? = ""
internal var manufacturer: String? = ""
internal var model: String? = ""
internal var os: String? = ""
internal var osVersion: String? = ""
internal var screenHeight: Int = 0
internal var screenWidth: Int = 0
internal var wifi: Int = 0
internal var sign1: String? = ""
internal var sign2: String? = ""
internal var sign3: String? = ""
internal var sign4: String? = ""
internal var sign5: String? = ""
fun partId(partId: String = ""): Builder {
this.partId = partId
return this
}
fun position(position: String = ""): Builder {
this.position = position
return this
}
fun uid(uid: String = ""): Builder {
this.uid = uid
return this
}
fun time(time: Long = 0.toLong()): Builder {
this.time = time
return this
}
fun ip(ip: String = ""): Builder {
this.ip = ip
return this
}
fun appVersion(appVersion: String = ""): Builder {
this.appVersion = appVersion
return this
}
fun appId(appId: String = ""): Builder {
this.appId = appId
return this
}
fun url(url: String = ""): Builder {
this.url = url
return this
}
fun server(server: String = ""): Builder {
this.server = server
return this
}
fun api(api: String = ""): Builder {
this.api = api
return this
}
fun manufacturer(manufacturer: String = ""): Builder {
this.manufacturer = manufacturer
return this
}
fun model(model: String = ""): Builder {
this.model = model
return this
}
fun os(os: String = ""): Builder {
this.os = os
return this
}
fun osVersion(osVersion: String = ""): Builder {
this.osVersion = osVersion
return this
}
fun screenHeight(screenHeight: Int = 0): Builder {
this.screenHeight = screenHeight
return this
}
fun screenWidth(screenWidth: Int = 0): Builder {
this.screenWidth = screenWidth
return this
}
fun wifi(wifi: Int = 0): Builder {
this.wifi = wifi
return this
}
fun sign1(sign1: String = ""): Builder {
this.sign1 = sign1
return this
}
fun sign2(sign2: String = ""): Builder {
this.sign2 = sign2
return this
}
fun sign3(sign3: String = ""): Builder {
this.sign3 = sign3
return this
}
fun sign4(sign4: String = ""): Builder {
this.sign4 = sign4
return this
}
fun sign5(sign5: String = ""): Builder {
this.sign5 = sign5
return this
}
fun build() : ActionDataBean {
return ActionDataBean(this)
}
}
}
\ No newline at end of file
package com.ydl.ydl_pay.actionpoint
/**
* Created by xj on 2019/7/1.
*/
internal class BIConstants{
companion object {
/**
* 消息端来源
*/
const val APP_ID = "ydl-app-android-user" //这是用户端主包的
/**
* 操作系统
*/
const val OS = "Android" //android系统
/**
* 埋点板块
*/
const val PART_ID_COURSE_COUPON_PAGE= "course_coupon_page"//课程兑换码弹出页
/**
* position
* 点击类型
*/
const val POSITION_COURSE_COUPON_CLICK = "course_coupon_click" //课程兑换券点击
}
}
\ No newline at end of file
package com.ydl.ydl_pay.adapter
import android.annotation.SuppressLint
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.ydl.ydl_pay.actionpoint.ActionCountUtils
import com.ydl.ydl_pay.actionpoint.BIConstants
import com.ydl.ydl_pay.http.HttpConfig
import com.ydl.ydl_pay.widget.CouponInfoDetailView
import com.yidianling.ydl_pay.R
import com.yidianling.ydl_pay.bean.AllCouponListBean
import com.yidianling.ydl_pay.bean.CommonCouponBean
import kotlinx.android.synthetic.main.item_coupon_title.view.*
/**
* @author jiucheng
* @描述:选择优惠券adpater
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/19
*/
class SelectCouponAdapter(var couponListBean: AllCouponListBean, var context: Context, var event: (selectedCouponBean: CommonCouponBean?) -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var headView: View? = null
companion object {
//可用优惠券title
const val TYPE_AVAILABLE_TITLE = 0
//可用优惠券内容
const val TYPE_AVAILABLE_CONTENT = 1
//不可用优惠券title
const val TYPE_UNAVAILABLE_TITLE = 2
//不可用优惠券内容
const val TYPE_UNAVAILABLE_CONTENT = 3
//headview
const val TYPE_HEAD = 1024
}
fun setHeadView(headView: View) {
this.headView = headView
}
private fun getHeadVieCount(): Int {
return if (headView == null) 0 else 1
}
override fun getItemViewType(position: Int): Int {
if (getHeadVieCount() > 0) { //有头部布局
if (position == 0) {
return TYPE_HEAD
}
//可用优惠券为0
if (couponListBean.availableCount == 0) {
return if (position == 1) {
TYPE_UNAVAILABLE_TITLE
} else {
TYPE_UNAVAILABLE_CONTENT
}
}
return if (position == 1) {
//可用优惠券title
TYPE_AVAILABLE_TITLE
} else if (position > 1 && position <= couponListBean.availableCount + 1) {
//可用优惠券
TYPE_AVAILABLE_CONTENT
} else if (position == couponListBean.availableCount + 2) {
//不可用优惠券title
TYPE_UNAVAILABLE_TITLE
} else {
//不可用优惠券
TYPE_UNAVAILABLE_CONTENT
}
} else {
//可用优惠券为0
if (couponListBean.availableCount == 0) {
return if (position == 0) {
TYPE_UNAVAILABLE_TITLE
} else {
TYPE_UNAVAILABLE_CONTENT
}
}
return if (position == 0) {
//可用优惠券title
TYPE_AVAILABLE_TITLE
} else if (position > 0 && position <= couponListBean.availableCount) {
//可用优惠券
TYPE_AVAILABLE_CONTENT
} else if (position == couponListBean.availableCount + 1) {
//不可用优惠券title
TYPE_UNAVAILABLE_TITLE
} else {
//不可用优惠券
TYPE_UNAVAILABLE_CONTENT
}
}
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
TYPE_HEAD -> {
HeadViewHolder(headView!!)
}
TYPE_AVAILABLE_TITLE -> {
TitleViewHolder(LayoutInflater.from(context).inflate(R.layout.item_coupon_title, null))
}
TYPE_AVAILABLE_CONTENT -> {
CouponViewHolder(CouponInfoDetailView(context))
}
TYPE_UNAVAILABLE_TITLE -> {
TitleViewHolder(LayoutInflater.from(context).inflate(R.layout.item_coupon_title, null))
}
TYPE_UNAVAILABLE_CONTENT -> {
CouponViewHolder(CouponInfoDetailView(context))
}
else -> {
TitleViewHolder(LayoutInflater.from(context).inflate(R.layout.item_coupon_title, null))
}
}
}
override fun getItemCount(): Int {
if (couponListBean.availableCount + couponListBean.unAvailableCount > 0) {
//如果没有可用优惠券,那可用优惠券标题和内容都不显示
if (couponListBean.availableCount == 0) {
return couponListBean.unAvailableCount + 1 + getHeadVieCount()
}
return couponListBean.availableCount + couponListBean.unAvailableCount + 2 + getHeadVieCount()
} else {
return 0 + getHeadVieCount()
}
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
when (getItemViewType(position)) {
TYPE_HEAD -> {
}
TYPE_AVAILABLE_TITLE -> {
(holder as TitleViewHolder).textView!!.text = "可用券(${couponListBean.availableCount})"
}
TYPE_AVAILABLE_CONTENT -> {
var realPosition = if (getHeadVieCount() == 0) position else position - 1
(holder as CouponViewHolder).view.setData(couponListBean.available[realPosition - 1], true)
holder.view.setOnClickListener {
//点击的优惠券是未选中的
if (couponListBean.available[realPosition - 1].hasSelected != 1) {
repeat(couponListBean.available.size) {
couponListBean.available[it].hasSelected = 0
}
couponListBean.available[realPosition - 1].hasSelected = 1
ActionCountUtils.count(HttpConfig.uid, BIConstants.PART_ID_COURSE_COUPON_PAGE,
BIConstants.POSITION_COURSE_COUPON_CLICK, "", "", couponListBean.available[realPosition - 1].couponId)
notifyDataSetChanged()
event(couponListBean.available[realPosition - 1])
} else { //点击的优惠券是选中的
couponListBean.available[realPosition - 1].hasSelected = 0
ActionCountUtils.count(HttpConfig.uid, BIConstants.PART_ID_COURSE_COUPON_PAGE,
BIConstants.POSITION_COURSE_COUPON_CLICK, "", "", "")
notifyDataSetChanged()
event(null)
}
}
}
TYPE_UNAVAILABLE_TITLE -> {
(holder as TitleViewHolder).textView!!.text = "不可用券(${couponListBean.unAvailableCount})"
}
TYPE_UNAVAILABLE_CONTENT -> {
var realPosition = if (getHeadVieCount() == 0) position else position - 1
if (couponListBean.unAvailableCount > 0) {
if (couponListBean.availableCount == 0) {
(holder as CouponViewHolder).view.setData(couponListBean.unAvailable[realPosition - 1], false)
} else {
(holder as CouponViewHolder).view.setData(couponListBean.unAvailable[realPosition - couponListBean.availableCount - 2], false)
}
}
}
}
}
inner class CouponViewHolder(var view: CouponInfoDetailView) : RecyclerView.ViewHolder(view)
inner class HeadViewHolder(var view: View) : RecyclerView.ViewHolder(view)
inner class TitleViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
var textView: TextView? = null
init {
textView = this.view.tv_title
}
}
}
package com.yidianling.ydl_pay.bean;
import java.util.ArrayList;
import java.util.List;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/18
*/
public class AllCouponListBean {
public int availableCount;
public List<CommonCouponBean> available = new ArrayList<>();
public List<CommonCouponBean> unAvailable = new ArrayList<>();
public int unAvailableCount;
}
package com.yidianling.ydl_pay.bean;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/17
*/
public class CheckCourseCouponBean {
/**
* "isAvailable": false,
* "couponInfo": null,
* "msg": "",
* "msgCode": "课程不存在"
*/
public boolean isAvailable = false;
public String msg;
public String msgCode;
}
package com.yidianling.ydl_pay.bean;
import java.util.List;
/**
* @author jiucheng
* @描述:优惠券的bean
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/17
*/
public class CommonCouponBean {
public float amount;//优惠金额
public float combinedAmount;//合计优惠金额
public String couponType;//券类型 1兑换券 2新优惠券(优先判断这个)
public String discount;//折扣
public String discountCont;//优惠的文案
public String effective;//有效期的文案
public String endDate;//截止有效期 ,
public String code;//code +type 可组成唯一标识
public boolean isAvailableCoupon;
public boolean isAvailableMaxCoupon;
public boolean isReceiveCoupon;
public boolean isTheFailure;// 是否即将过期 true是 2false ,
public float price;//兑换券的金额
public String type;//优惠券形式:1立减,2折扣 ,
public String rangeCont;//使用范围的文案
public List<String> specifiedGoodsList;//指定商品列表
public int isSpecifiedGoods;//是否指定商品 1是 2否 ,
public String couponId;//优惠券id
public String title;//优惠券名称 ,
public String validityType;//有效期类型:1永久有效,2指定日期
public String id;// 用户领用记录的id(不是优惠券id)
public String useCondition;// 使用条件 1无限制 2满金额
public float useConditionValue;//使用条件的值(金额或次数) ,
//是否选中 0 未选中 1 选中
public int hasSelected = 0;
}
package com.yidianling.ydl_pay.bean;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/23
*/
public class CommonPayRecharge {
public String rechargeId;
/**
* 支付金额
*/
public String money;
/**
* 支付宝 加签
*/
public String aliSign;
}
package com.ydl.ydl_pay.bean
/**
* author : Zhangwenchao
* e-mail : zhangwch@yidianling.com
* time : 2018/04/18
*/
data class CommonWXPayBean(val option: WXOption) {
data class WXOption(val appid: String,
val timestamp: String,
val noncestr: String,
val partnerid: String,
val prepayid: String,
val sign: String)
}
\ No newline at end of file
package com.yidianling.ydl_pay.bean;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/19
*/
public class CouponCodeInfoBean {
public boolean isAvailable;//是否可用
public String msg;//是否可用
public String msgCode;//错误码
public CommonCouponBean couponInfo;//优惠券信息
}
package com.yidianling.ydl_pay.bean;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/16
*/
public class OrderInfoBean {
/**
* applyFee (number, optional): 课程金额 ,
* availableMoney (number, optional): 现金余额 ,
* goodsId (integer, optional): 对应的商品id ,
* isShowCoupon (boolean, optional): 是否展示优惠入口 true展示 false不展示 ,
* isVirtual (string, optional): 虚拟商品 1是 2不是 ,
* orderType (string, optional): 业务类型 1课程 ,
* title (string, optional): 商品名称 ,
* ybBalance (number, optional): 壹贝金额
*/
public float applyFee;
public float availableMoney;
public String goodsId;
public boolean isShowCoupon;
public String isVirtual;
public String orderType;
public String title;
//ios 壹贝字段
public String ybBalance;
public CommonCouponBean maxCoupon;
}
package com.yidianling.ydl_pay.bean;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/22
*/
public class PayOrderBean {
public String orderId;//订单id
public String payId;//支付id
public String payWay;//1调用三方支付 2调用充值接口
public String title;//业务名称
public String uid;//用户id
public float rechargeMoney;//需要充值的金额
public boolean payStatus;//支付状态 true已支付 false未支付 ,
}
package com.yidianling.ydl_pay.bean; import android.text.TextUtils; import java.util.Map; public class PayResult { private String resultStatus; private String result; private String memo; public PayResult(Map<String, String> rawResult) { if (rawResult == null) { return; } for (String key : rawResult.keySet()) { if (TextUtils.equals(key, "resultStatus")) { resultStatus = rawResult.get(key); } else if (TextUtils.equals(key, "result")) { result = rawResult.get(key); } else if (TextUtils.equals(key, "memo")) { memo = rawResult.get(key); } } } @Override public String toString() { return "resultStatus={" + resultStatus + "};memo={" + memo + "};result={" + result + "}"; } /** * @return the resultStatus */ public String getResultStatus() { return resultStatus; } /** * @return the memo */ public String getMemo() { return memo; } /** * @return the result */ public String getResult() { return result; }}
\ No newline at end of file
package com.ydl.ydl_pay.bean
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/5/7
*/
data class WeiXinPayStatusEvent(val success: Boolean, val msg: String?)
\ No newline at end of file
package com.yidianling.ydl_pay.bean.params;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/24
*/
public class AliPayParam extends CommonPayParam {
public AliPayParam(String payId,int isThreePay) {
super(payId, "aliapp",isThreePay);
}
}
package com.yidianling.ydl_pay.bean.params;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/23
*/
public class BalancePayParam extends BaseCommand {
public String payId;
}
package com.yidianling.ydl_pay.bean.params;
import com.ydl.ydl_pay.http.HttpConfig;
/**
* 基础网络请求类
* Created by Dog on 2015/5/8.
*/
public class BaseCommand {
public String uid = HttpConfig.INSTANCE.getUid();
public String accessToken = HttpConfig.INSTANCE.getAccessToken();
public String ts;
public String version = HttpConfig.INSTANCE.getVersion();
public String osBuild = HttpConfig.INSTANCE.getOsBuild();
public String isFromApp = "1";//2表示专家版1表示用户版
public String ffrom = HttpConfig.INSTANCE.getFfrom();//渠Y道来源
public BaseCommand() {
ts = (System.currentTimeMillis() / 1000) + "";
}
}
package com.yidianling.ydl_pay.bean.params;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/17
*/
public class CheckRequestCouponBean {
public String couponCode;//兑换券码 ,
public String courseId;// 课程id
}
package com.yidianling.ydl_pay.bean.params;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/23
*/
public class CommonPayParam extends BaseCommand {
public String payId;
public String type;
public int isThreePay = 0;//混合支付 0 纯三方支付 isThreePay 1
public CommonPayParam(String payId, String type, int isThreePay) {
this.payId = payId;
this.isThreePay = isThreePay;
this.type = type;
}
}
package com.yidianling.ydl_pay.bean.params;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/22
*/
public class CreateOrderRequestBean {
public String code;//优惠券code
public String couponType ;//券类型 1兑换券 2新优惠券 ,
public String goodsId;//商品id ,
public String orderType;//业务类型 1课程 ,
public String payType;//1余额,2三方支付,3混合 4壹贝(ios的虚拟商品)
}
package com.yidianling.ydl_pay.bean.params;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/18
*/
public class GetAllCouponRequestBean {
public String applyEnds;// 适用终端 1PC官网 2wap站点 3用户app 4好杮app 5专家app ,
public String goodsId;// 商品Id
public String receiveType = "1";// 领取条件方式 1前台领取 2链接领取 ,
public String services;//适用服务 1预约咨询 2电话倾诉 3课程(用户课程 专家课程) 5测评
}
package com.yidianling.ydl_pay.bean.params;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/16
*/
public class OrderRequestBean {
/**
* goodsId (integer, optional): 商品id ,
* orderType (string, optional): 业务类型 1课程
*/
public String goodsId;
public String orderType;
}
package com.yidianling.ydl_pay.bean.params;
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/24
*/
public class WxPayParam extends CommonPayParam {
public WxPayParam(String payId, int isThreePay) {
super(payId, "wxapp_hz", isThreePay);
}
}
package com.yidianling.ydl_pay.http;
/**
* Post请求表单
*/
public class FormatText {
//key
private String mKey;
//value
private String mValue;
public FormatText(String mKey, String mValue) {
this.mKey = mKey;
this.mValue = mValue;
}
public String getmKey() {
return mKey;
}
public String getmValue() {
return mValue;
}
@Override
public String toString() {
return "FormatText{" +
"mKey='" + mKey + '\'' +
", mValue='" + mValue + '\'' +
'}';
}
}
package com.ydl.ydl_pay.http
/**
* @author jiucheng
* @描述: 网络请求的一些基本参数
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/3
*/
object HttpConfig {
var ffrom = ""
/**
* //1表示用户版2表示专家版
*/
var isFromApp = "1"
var version = ""
var osBuild = ""
var accessToken = ""
var uid = ""
/**
* 调试参数:
*仅在debug包下切换环境使用
*
*
* true 测试环境 false 线上环境
* 默认测试环境
*
*
* release包 此参数无效
*/
var isTestEnvironment = true
}
\ No newline at end of file
package com.ydl.ydl_pay.http
import com.google.gson.Gson
import com.ydl.ydl_pay.BuildConfig
import com.ydl.ydl_pay.actionpoint.ActionDataBean
import com.ydl.ydl_pay.bean.*
import com.ydl.ydl_pay.bean.params.*
import com.ydl.ydl_pay.http.response.BaseResponse
import com.ydl.ydl_pay.http.utils.HttpUrlUtils
import com.ydl.ydl_pay.http.utils.NetUtils
import com.ydl.ydl_pay.http.utils.RxHttpUtils
import io.reactivex.Observable
import okhttp3.MediaType
import okhttp3.RequestBody
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/17
*/
class HttpUtils {
companion object {
/**
* 获取下单的信息
*/
fun getOrderInfo(bean: OrderRequestBean): Observable<BaseResponse<OrderInfoBean>> {
var str = Gson().toJson(bean)
val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), str) as RequestBody
return PayRetrofitUtils.getRetrofit().create(PayServices::class.java).getOrderInfo(body)
}
/**
* 验证课程兑换券是否可用
*/
fun checkCourseCoupon(bean: CheckRequestCouponBean): Observable<BaseResponse<CouponCodeInfoBean>> {
var str = Gson().toJson(bean)
val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), str) as RequestBody
return PayRetrofitUtils.getRetrofit().create(PayServices::class.java).checkCourseCoupon(body)
}
/**
* 下单时候选择优惠券
*/
fun selectCoupon(bean: GetAllCouponRequestBean): Observable<BaseResponse<AllCouponListBean>> {
var str = Gson().toJson(bean)
val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), str) as RequestBody
return PayRetrofitUtils.getRetrofit().create(PayServices::class.java).selectCoupon(body)
}
/**
* 创建订单
*/
fun createOrder(bean: CreateOrderRequestBean): Observable<BaseResponse<PayOrderBean>> {
var str = Gson().toJson(bean)
val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), str) as RequestBody
return PayRetrofitUtils.getRetrofit().create(PayServices::class.java).createOrder(body)
}
/**
* 支付宝在线支付
*/
fun getAliPayOrderId(bean: BaseCommand): Observable<BaseResponse<CommonPayRecharge>> {
var params = PayRetrofitUtils.getPostList(bean)
var map = PayRetrofitUtils.getMaps(params)
return PayRetrofitUtils.getRetrofit().newBuilder().baseUrl(HttpUrlUtils.getBaseUrl(HttpConfig.isTestEnvironment, false))
.build().create(PayServices::class.java).getAliPayOrderId(map)
}
/**
* 微信在线支付
*/
fun wxPay(bean: BaseCommand): Observable<BaseResponse<CommonWXPayBean>> {
var params = PayRetrofitUtils.getPostList(bean)
var map = PayRetrofitUtils.getMaps(params)
return PayRetrofitUtils.getRetrofit().newBuilder().baseUrl(HttpUrlUtils.getBaseUrl(HttpConfig.isTestEnvironment, false)).build().create(PayServices::class.java).wxPay(map)
}
/**
* 行为数据埋点统计接口
*/
internal fun actionDataCount(actionDataParams: ActionDataBean): Observable<BaseResponse<String>> {
val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), Gson().toJson(actionDataParams))
return PayRetrofitUtils.getRetrofit().newBuilder().baseUrl(HttpUrlUtils.geActionUrl(HttpConfig.isTestEnvironment)).build().create(PayServices::class.java).actionDataCount(body)
}
}
}
package com.ydl.ydl_pay.http
import android.annotation.SuppressLint
import com.facebook.stetho.okhttp3.StethoInterceptor
import com.ydl.ydl_pay.BuildConfig
import com.ydl.ydl_pay.bean.params.BaseCommand
import com.ydl.ydl_pay.http.log.LogUtil
import com.ydl.ydl_pay.http.utils.HttpUrlUtils
import okhttp3.FormBody
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import okio.Buffer
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.security.KeyManagementException
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.security.SecureRandom
import java.security.cert.X509Certificate
import java.util.*
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
/**
* @author jiucheng
* @描述:支付模块的网络请求
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/3
*/
class PayRetrofitUtils private constructor() {
private lateinit var config: HttpConfig
companion object {
private const val AUTHORIZATION_NAME = "Authorization"
private const val SESSION_KEY_DEFAULT_VALUE = "dc59cf294f37d237c1f06240568ffe21"
private const val YDL = "Ydl "
private const val UID = "uid"
private const val FFROM = "ffrom"
private const val IS_FROM_APP = "isFromApp"//1表示用户版2表示专家版
private const val OS_BUILD = "osBuild"
private const val TS = "ts"
private const val VERSION = "version"
private const val TOKEN = "accessToken"
private const val DEFAULT_TIMEOUT = 15
private const val OS_TYPE = "osType"// 1.ios 2.android
private fun getInstance(): PayRetrofitUtils {
return Holder.INSTANCE
}
fun setConfig(config: HttpConfig) {
getInstance().config = config
}
// 调用此方法获取 Retrofit 对象
fun getRetrofit(): Retrofit {
return getInstance().retrofit
}
fun getPostList(crq: BaseCommand): List<FormatText> {
val formTextList = ArrayList<FormatText>()
val fields = crq.javaClass.fields
for (field in fields) {
try {
val accessFlag = field.isAccessible
field.isAccessible = true
val o = field.get(crq)
if (o != null) {
val formatText = FormatText(field.name, o.toString())
formTextList.add(formatText)
}
field.isAccessible = accessFlag
} catch (e: IllegalAccessException) {
e.printStackTrace()
}
}
return formTextList
}
//获取网络请求表
fun getMaps(list: List<FormatText>): Map<String, String> {
val map = HashMap<String, String>()
val size = list.size
for (i in 0 until size) {
val formatText = list[i]
map[formatText.getmKey()] = formatText.getmValue().toString()
}
return map
}
}
private val retrofit: Retrofit by lazy {
Retrofit.Builder()
.baseUrl(getBaseJavaUrl())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(getOkHttp())
.build()
}
private fun getBaseJavaUrl(): String {
return HttpUrlUtils.getBaseUrl(config.isTestEnvironment, true)
}
private fun getOkHttp(): OkHttpClient {
val builder = OkHttpClient.Builder()
builder.retryOnConnectionFailure(false)
builder.addInterceptor { chain ->
val body = chain.request().body()
val list = ArrayList<FormatText>()
if (body is FormBody) {
val formBody = body as FormBody?
for (i in 0 until formBody!!.size()) {
list.add(FormatText(formBody.name(i), formBody.value(i)))
}
}
if (body is MultipartBody) {
val multipartBody = body as MultipartBody?
val parts = multipartBody!!.parts()
for (part in parts) {
if ("text/plain; charset=utf-8" == part.body().contentType()!!.toString()) {
val headerStr = part.headers()!!.toString()
val name = headerStr.split("\"\\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0].split("=\"".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1]
val buffer = Buffer()
part.body().writeTo(buffer)
val value = buffer.readUtf8()
list.add(FormatText(name, value))
}
}
}
val head = YDL + getSign(list)
LogUtil.i("RetrofitLog", "head = $head")
val build = chain.request()
.newBuilder()
.header(AUTHORIZATION_NAME, head)
.addHeader(FFROM, config.ffrom)
.addHeader(IS_FROM_APP, config.isFromApp)
.addHeader(VERSION, config.version)
.addHeader(OS_BUILD, config.osBuild)
.addHeader(OS_TYPE, "2")
.addHeader(TOKEN, config.accessToken)
.addHeader(TS, (System.currentTimeMillis() / 1000).toString())
.addHeader(UID, config.uid)
chain.proceed(build.build())
}
if (BuildConfig.DEBUG) {
builder.addInterceptor(HttpLoggingInterceptor { message ->
//打印retrofit日志
LogUtil.i("RetrofitLog", "retrofitBack = $message")
}.setLevel(HttpLoggingInterceptor.Level.BODY))
builder.addNetworkInterceptor(StethoInterceptor())
}
//使用自定义SSLSocketFactory
val factory = createSSLSocketFactory()
if (factory != null) {
builder.sslSocketFactory(factory)
.hostnameVerifier { _, _ -> true }
}
builder.connectTimeout(DEFAULT_TIMEOUT.toLong(), TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT.toLong(), TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT.toLong(), TimeUnit.SECONDS)
return builder.build()
}
//获取请求头签名
private fun getSign(list: List<FormatText>): String? {
//将请求参数倒序排列
Collections.sort(list, SortData())
val stringBuilder = StringBuilder()
val size = list.size
for (i in 0 until size) {
val formatText = list[i]
if (i != 0) {
stringBuilder.append("&")
}
stringBuilder.append(String.format("%s=%s", formatText.getmKey(), formatText.getmValue()))
}
stringBuilder.append(SESSION_KEY_DEFAULT_VALUE)
return digestMD5(stringBuilder.toString())
}
//用来命名排序规则的
internal class SortData : Comparator<FormatText> {
override fun compare(lhs: FormatText, rhs: FormatText): Int {
val res = lhs.getmKey().compareTo(rhs.getmKey())
if (res == 0) {
return 0
}
return if (res > 0) -1 else 1
}
}
/**
* 用于MD5加密
*
* @param clear 明文
* @return 密文
*/
private fun digestMD5(clear: String): String? {
val hexDigits = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f')
try {
val strTemp = clear.toByteArray(charset("utf-8"))
// 使用MD5创建MessageDigest对象
val mdTemp = MessageDigest.getInstance("MD5")
mdTemp.update(strTemp)
val md = mdTemp.digest()
val j = md.size
val str = CharArray(j * 2)
var k = 0
for (b in md) {
// 将每个数(int)b进行双字节加密
str[k++] = hexDigits[b.toInt() shr 4 and 0xf]
str[k++] = hexDigits[b.toInt() and 0xf]
}
return String(str)
} catch (e: Exception) {
return null
}
}
/**
* 默认信任所有的证书
*/
@SuppressLint("TrustAllX509TrustManager")
private fun createSSLSocketFactory(): SSLSocketFactory? {
val xtm = object : X509TrustManager {
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {}
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {}
override fun getAcceptedIssuers(): Array<X509Certificate?> {
return arrayOfNulls(0)
}
}
val sslContext: SSLContext
try {
sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, arrayOf<TrustManager>(xtm), SecureRandom())
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
return null
} catch (e: KeyManagementException) {
e.printStackTrace()
return null
}
return sslContext.socketFactory
}
private object Holder {
val INSTANCE = PayRetrofitUtils()
}
}
\ No newline at end of file
package com.ydl.ydl_pay.http
import com.ydl.ydl_pay.bean.*
import com.ydl.ydl_pay.http.response.BaseResponse
import io.reactivex.Observable
import okhttp3.RequestBody
import retrofit2.http.Body
import retrofit2.http.FieldMap
import retrofit2.http.FormUrlEncoded
import retrofit2.http.POST
/**
* @author jiucheng
* @描述:支付相关的接口
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/16
*/
interface PayServices {
/**
* 获取下单的信息
*/
@POST("auth/Order/getOrderInfo")
fun getOrderInfo(@Body body: RequestBody): Observable<BaseResponse<OrderInfoBean>>
/**
* 验证课程兑换券是否可用
*/
@POST("auth/course/checkCourseCoupon")
fun checkCourseCoupon(@Body body: RequestBody): Observable<BaseResponse<CouponCodeInfoBean>>
/**
* 下单时候选择优惠券
*/
@POST("auth/new_coupon/selectCoupon")
fun selectCoupon(@Body body: RequestBody): Observable<BaseResponse<AllCouponListBean>>
/**
* 创建订单
*/
@POST("auth/Order/createOrder")
fun createOrder(@Body body: RequestBody): Observable<BaseResponse<PayOrderBean>>
/**
* 支付宝在线支付
*/
@FormUrlEncoded
@POST("pay/get-recharge")
fun getAliPayOrderId(@FieldMap params: Map<String, String>): Observable<BaseResponse<CommonPayRecharge>>
/**
* 微信在线支付
*/
@FormUrlEncoded
@POST("pay/to-pay")
fun wxPay(@FieldMap params: Map<String, String>): Observable<BaseResponse<CommonWXPayBean>>
//行为动作埋点统计接口
@POST("maidian/writeMaiDianData")
fun actionDataCount(@Body body: RequestBody): Observable<BaseResponse<String>>
}
\ No newline at end of file
package com.yidianling.ydl_pay.http.log;
import android.util.Log;
import com.ydl.ydl_pay.BuildConfig;
/**
* LogUtil
* Created by Jim on 2017/11/2 0002.
*/
@SuppressWarnings("unused")
public class LogUtil {
private static String className;//类名
private static String methodName;//方法名
private static int lineNumber;//行数
private static String lastMethodName;
private static boolean debug = BuildConfig.DEBUG;
public static String TAG = "hzs";
private LogUtil() {
}
private static String printLog(String log) {
return "| " + Thread.currentThread().getName() + " | " +
lastMethodName+"() -->" + methodName + "() | " +
" (" + className + ":" + lineNumber + ") | " +
log;
}
private static void getMethodNames(StackTraceElement[] sElements) {
className = sElements[1].getFileName();
methodName = sElements[1].getMethodName();
lineNumber = sElements[1].getLineNumber();
lastMethodName=sElements[2].getMethodName();
}
public static void e(String message) {
if (debug) {
getMethodNames(new Throwable().getStackTrace());
Log.e(TAG, printLog(message));
}
}
public static void e(String tag, String message) {
if (debug) {
getMethodNames(new Throwable().getStackTrace());
Log.e(TAG + "_" + tag, printLog(message));
}
}
public static void i(String message) {
if (debug) {
getMethodNames(new Throwable().getStackTrace());
Log.i(TAG, printLog(message));
}
}
public static void i(String tag, String message) {
if (debug) {
getMethodNames(new Throwable().getStackTrace());
Log.i(TAG + "_" + tag, printLog(message));
}
}
public static void d(String message) {
if (debug) {
getMethodNames(new Throwable().getStackTrace());
Log.d(TAG, printLog(message));
}
}
public static void d(String tag, String message) {
if (debug) {
getMethodNames(new Throwable().getStackTrace());
Log.d(TAG + "_" + tag, printLog(message));
}
}
public static void v(String message) {
if (debug) {
getMethodNames(new Throwable().getStackTrace());
Log.v(TAG, printLog(message));
}
}
public static void v(String tag, String message) {
if (debug) {
getMethodNames(new Throwable().getStackTrace());
Log.v(TAG + "_" + tag, printLog(message));
}
}
public static void w(String message) {
if (debug) {
getMethodNames(new Throwable().getStackTrace());
Log.w(TAG, printLog(message));
}
}
public static void w(String tag, String message) {
if (debug) {
getMethodNames(new Throwable().getStackTrace());
Log.w(TAG + "_" + tag, printLog(message));
}
}
public static void wtf(String message) {
if (debug) {
getMethodNames(new Throwable().getStackTrace());
Log.wtf(TAG, printLog(message));
}
}
}
package com.yidianling.ydl_pay.http.response;
import com.google.gson.annotations.SerializedName;
/**
* 基础返回数据类
* Created by Dog on 2015/5/8.
*/
public class BaseResponse<T> {
public int code;
public String msg;
public int status;
@SerializedName("total_page")
public int totalPage;
public T data;
}
package com.yidianling.ydl_pay.http.utils;
import com.ydl.ydl_pay.BuildConfig;
/**
* @author jiucheng
* @描述:获取api的baseUrl
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/23
*/
public class HttpUrlUtils {
private static final String JAVA_BASE_URL = "https://api.ydl.com/api/";
private static final String ACTION_BASE_URL = "https://api.ydl.com/api/data/bigdata/";
private static final String PHP_BASE_URL = "https://app2.yidianling.com/v3/";
private static final String DEBUG_JAVA_BASE_URL = "http://testapi.ydl.com/api/";
private static final String DEBUG_PHP_BASE_URL = "https://testapp2.yidianling.com/v3/";
private static final String DEBUG_ACTION_BASE_URL = "https://testapi.ydl.com/api/data/bigdata/";
/**
* 获取baseUrl
*
* @param isTestEnvironment 是否是测试环境
* @param isJava 是否是java url
* @return
*/
public static String getBaseUrl(boolean isTestEnvironment, boolean isJava) {
String baseUrl;
if (BuildConfig.DEBUG) {//debug包
if (isTestEnvironment) {//测试环境
if (isJava) {
baseUrl = DEBUG_JAVA_BASE_URL;
} else {
baseUrl = DEBUG_PHP_BASE_URL;
}
} else {
if (isJava) {
baseUrl = JAVA_BASE_URL;
} else {
baseUrl = PHP_BASE_URL;
}
}
} else {//release 包
if (isJava) {
baseUrl = JAVA_BASE_URL;
} else {
baseUrl = PHP_BASE_URL;
}
}
return baseUrl;
}
/**
* 获取埋点的baseurl
*
* @param isTestEnvironment 是否是测试环境
* @return
*/
public static String geActionUrl(boolean isTestEnvironment) {
String baseUrl;
if (BuildConfig.DEBUG) {//debug包
if (isTestEnvironment) {//测试环境
baseUrl = DEBUG_ACTION_BASE_URL;
} else {
baseUrl = ACTION_BASE_URL;
}
} else {//release 包
baseUrl = DEBUG_ACTION_BASE_URL;
}
return baseUrl;
}
}
package com.ydl.ydl_pay.http.utils
import com.ydl.ydl_pay.http.response.BaseResponse
import io.reactivex.Observable
import io.reactivex.ObservableTransformer
import java.net.ConnectException
/**
* author : Zhangwenchao
* e-mail : zhangwch@yidianling.com
*/
object RxHttpUtils {
/**
* 根据返回数据,得到真正需要的数据
* 若状态码不为0,抛出接口异常
*/
@JvmStatic
fun <T> resultData(): ObservableTransformer<BaseResponse<T>, T> {
return ObservableTransformer {
it.flatMap {
if (it.code == 0) Observable.just(it.data)
else Observable.error(Throwable(it.msg))
}
}
}
}
package com.ydl.ydl_pay.toast
import android.content.Context
import android.support.annotation.StringRes
import android.text.TextUtils
import android.widget.Toast
/**
* author : Zhangwenchao
* e-mail : zhangwch@yidianling.com
* time : 2018/01/29
*
* 提示信息的封装类,使用单例 toast,防止重复弹出提示
*/
class ToastHelper private constructor() {
private var toast: Toast? = null
companion object {
private fun getInstance(): ToastHelper {
return Holder.INSTANCE
}
fun show(context: Context, text: String) {
getInstance().show(context.applicationContext, text)
}
fun show(context: Context, @StringRes resId: Int) {
getInstance().show(context.applicationContext, resId)
}
}
private fun show(context: Context, text: CharSequence) {
if (TextUtils.isEmpty(text)) return
if (toast == null) toast = Toast.makeText(context, text, Toast.LENGTH_SHORT)
else toast?.setText(text)
toast?.show()
}
private fun show(context: Context, @StringRes resId: Int) {
if (toast == null) toast = Toast.makeText(context, resId, Toast.LENGTH_SHORT)
else toast?.setText(resId)
toast?.show()
}
private object Holder {
val INSTANCE = ToastHelper()
}
}
package com.ydl.ydl_pay.widget
import android.annotation.SuppressLint
import android.content.Context
import android.text.TextUtils
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import com.yidianling.ydl_pay.R
import com.yidianling.ydl_pay.bean.CommonCouponBean
import kotlinx.android.synthetic.main.view_coupon_info_detail.view.*
import java.lang.Float
import java.math.BigDecimal
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/19
*/
class CouponInfoDetailView(context: Context) : RelativeLayout(context) {
init {
initView()
}
private fun initView() {
val params = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
layoutParams = params
View.inflate(context, R.layout.view_coupon_info_detail, this)
}
@SuppressLint("SetTextI18n")
fun setData(bean: CommonCouponBean, isUseAble: Boolean) {
if (bean.couponType == "1") {//1兑换券
tv_price.text = "¥" + bean.price
} else {//优惠券
tv_price.text = "¥" + bean.amount
if (bean.type == "1") {
tv_price.text = "¥" + bean.amount
} else {
val a1 = BigDecimal(Float.toString(bean.discount.toFloat()))
val b1 = BigDecimal(Float.toString(10f))
val result = a1.multiply(b1).toFloat()// 相乘结果
val discountStr = "${result}折"
tv_price.text = discountStr
}
}
if (bean.couponType == "1") {
tv_discountCont.text = "${bean.price}元以内可用"
tv_discountCont.visibility = View.VISIBLE
}
if (!TextUtils.isEmpty(bean.discountCont)) {
tv_discountCont.text = bean.discountCont
tv_discountCont.visibility = View.VISIBLE
}
if (TextUtils.isEmpty(bean.discountCont) && bean.useCondition == "1") {
tv_discountCont.text = "无限制"
tv_discountCont.visibility = View.VISIBLE
}
tv_title.text = bean.title
tv_duration.text = bean.effective
tv_use_condition.text = bean.rangeCont
if (bean.isTheFailure) {
iv_background.setBackgroundResource(R.drawable.bg_kgq)
} else {
iv_background.setBackgroundResource(R.drawable.item_coupon_background)
}
if (isUseAble) {
iv_select.visibility = View.VISIBLE
if (bean.hasSelected == 1) {
iv_select.setImageResource(R.drawable.img_coupon_selsect)
} else {
iv_select.setImageResource(R.drawable.img_no_select)
}
} else {
iv_select.visibility = View.GONE
tv_title.setTextColor(resources.getColor(R.color.color_666666))
tv_duration.setTextColor(resources.getColor(R.color.color_666666))
tv_use_condition.setTextColor(resources.getColor(R.color.color_666666))
iv_background.setBackgroundResource(R.drawable.item_coupon_background_unuse)
if (bean.isTheFailure) {
iv_background.setBackgroundResource(R.drawable.bg_dis_kgq)
}
}
}
}
package com.yidianling.ydl_pay.widget;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* @author jiucheng
* @描述:是否可左右滑动viewp
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2018/10/15
*/
public class NoScrollViewPager extends ViewPager {
private boolean isCanScroll = false;
public NoScrollViewPager(Context context) {
super(context);
}
public NoScrollViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setScanScroll(boolean isCanScroll) {
this.isCanScroll = isCanScroll;
}
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isCanScroll) {
return super.onTouchEvent(event);
} else {
return false;
}
}
@Override
public void setCurrentItem(int item, boolean smoothScroll) {
super.setCurrentItem(item, smoothScroll);
}
@Override
public void setCurrentItem(int item) {
super.setCurrentItem(item);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (isCanScroll) {
return super.onInterceptTouchEvent(event);
} else {
return false;
}
}
}
package com.ydl.ydl_pay.widget
import android.content.Context
import android.os.Handler
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
import com.ydl.ydl_pay.adapter.SelectCouponAdapter
import com.ydl.ydl_pay.http.HttpUtils
import com.ydl.ydl_pay.toast.ToastHelper
import com.yidianling.ydl_pay.R
import com.yidianling.ydl_pay.bean.AllCouponListBean
import com.yidianling.ydl_pay.bean.CommonCouponBean
import com.yidianling.ydl_pay.bean.params.CheckRequestCouponBean
import com.yidianling.ydl_pay.http.utils.NetUtils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.head_course_code_view.view.*
import kotlinx.android.synthetic.main.view_pay_coupon.view.*
/**
* @author jiucheng
* @描述:支付优惠券选择view
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/4
*/
class PayCouponView(context: Context) : LinearLayout(context) {
private var selectedCouponBean: CommonCouponBean? = null
private var couponListBean: AllCouponListBean? = null
private var listener: OnCouponClickListener? = null
private var goodsId: String? = null
private var adapter: SelectCouponAdapter? = null
private var hasUseCouponCode = false
private var courseCodeView: View? = null
private var rt_coupon_code: EditText? = null
private var tv_ensure: TextView? = null
init {
initView()
}
private fun initView() {
orientation = VERTICAL
val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
layoutParams = params
View.inflate(context, R.layout.view_pay_coupon, this)
rl_back.setOnClickListener {
hideSoftInput()
if (listener != null) {
listener!!.onBackClick(selectedCouponBean)
}
}
var linearLayoutManager = LinearLayoutManager(context)
rv_content.layoutManager = linearLayoutManager
}
/**
* 动态隐藏软键盘
*
* @param context 上下文
* @param edit 输入框
*/
private fun hideSoftInput() {
if (rt_coupon_code == null) {
return
}
rt_coupon_code!!.clearFocus()
val inputmanger = context
.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputmanger.hideSoftInputFromWindow(rt_coupon_code!!.windowToken, 0)
}
/**
验证兑换券是否可用
*/
private fun checkCourseCoupon(couponCode: String) {
hideSoftInput()
if (!NetUtils.isConnected(context)) {
ToastHelper.show(context, context.getString(R.string.net_error))
return
}
var bean = CheckRequestCouponBean()
bean.couponCode = couponCode
bean.courseId = goodsId
HttpUtils.checkCourseCoupon(bean)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
if (it.code == 200) {
if (it.data != null) {
if (it.data.couponInfo != null) {
hasUseCouponCode = true
selectedCouponBean = it.data.couponInfo
if (tv_ensure != null) {
tv_ensure!!.text = "取消使用"
}
clearSelectCoupon()
Handler().postDelayed({
if (listener != null) {
listener!!.onSelectCoupon(selectedCouponBean)
}
}, 300)
} else {
ToastHelper.show(context, it.data.msg)
}
} else {
ToastHelper.show(context, it.msg)
}
} else {
ToastHelper.show(context, it.msg)
}
}, { e ->
ToastHelper.show(context, e.message!!)
})
}
fun setListener(listener: OnCouponClickListener) {
this.listener = listener
}
/**
* 设置数据
*/
fun setData(couponListBean: AllCouponListBean, isCoursePay: Boolean, selectedCouponBean: CommonCouponBean?, goodsId: String) {
// rl_course.visibility = if (isCoursePay) View.VISIBLE else View.GONE
if (isCoursePay) {
if (courseCodeView == null) {
initCourseCodeView()
}
}
this.couponListBean = couponListBean
this.selectedCouponBean = selectedCouponBean
this.goodsId = goodsId
if (couponListBean.availableCount == 0 && couponListBean.unAvailableCount == 0) {
rl_empty.visibility = View.VISIBLE
// rv_content.visibility = View.GONE
} else {
if (this.selectedCouponBean == null && couponListBean.availableCount != 0) {
this.couponListBean!!.available[0].hasSelected = 1
this.selectedCouponBean = this.couponListBean!!.available[0]
}
}
adapter = SelectCouponAdapter(this.couponListBean!!, context) {
this.selectedCouponBean = it
hasUseCouponCode = false
if (tv_ensure != null) {
tv_ensure!!.text = "使用"
}
hideSoftInput()
Handler().postDelayed({
if (listener != null) {
listener!!.onSelectCoupon(it)
}
}, 300)
}
if (courseCodeView != null) {
adapter!!.setHeadView(courseCodeView!!)
}
rv_content.adapter = adapter
}
/**
* 输入课程兑换码
*/
private fun initCourseCodeView() {
courseCodeView = View.inflate(context, R.layout.head_course_code_view, null)
var parmas = RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
courseCodeView!!.layoutParams = parmas
rt_coupon_code = courseCodeView!!.rt_coupon_code
tv_ensure = courseCodeView!!.tv_ensure
rt_coupon_code!!.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
tv_ensure!!.isEnabled = !TextUtils.isEmpty(s) && s!!.length == 8
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
})
tv_ensure!!.setOnClickListener {
if (hasUseCouponCode) {
selectedCouponBean = null
tv_ensure!!.text = "使用"
hasUseCouponCode = false
} else {
checkCourseCoupon(rt_coupon_code!!.text.toString())
}
}
}
private fun clearSelectCoupon() {
if(couponListBean!!.available!=null){
repeat(couponListBean!!.available.size) {
couponListBean!!.available[it].hasSelected = 0
}
adapter!!.notifyDataSetChanged()
}
}
interface OnCouponClickListener {
//返回按钮
fun onBackClick(selectedCouponBean: CommonCouponBean?)
//选择了优惠券
fun onSelectCoupon(selectedCouponBean: CommonCouponBean?)
}
}
package com.ydl.ydl_pay.widget
import android.annotation.SuppressLint
import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import com.yidianling.ydl_pay.R
import com.yidianling.ydl_pay.bean.CommonCouponBean
import com.yidianling.ydl_pay.bean.OrderInfoBean
import kotlinx.android.synthetic.main.view_pay_info_detail.view.*
import java.math.BigDecimal
/**
* @author jiucheng
* @描述:支付详细信息view
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2019/4/4
*/
@SuppressLint("ViewConstructor")
class PayInfoDetailView(context: Context, var listener: OnCouponDetailClickListener) : LinearLayout(context) {
private var orderInfoBean: OrderInfoBean? = null
/**
* 是否使用余额
*/
private var isUseChange = true
/**
* 使用余额,余额是否足够
*/
private var isBalanceSufficient = false
//需要sdk(支付宝、微信)支付的金额
private var sdkPayMoney = 0.00f
/**
* 支付方式
* 1024.微信支付 1025.支付宝支付
*/
private var payWay = PAY_WECHAT
/**
* 支付类型
* 1余额,2三方支付,3混合
*/
private var useMoneyType = 1
/**
* 可用优惠券的数量
*/
private var availableCount: Int = 0
companion object {
/**
* 支付方式
* 1024.微信支付 1025.支付宝支付
*/
private const val PAY_WECHAT = 1024
private const val PAY_ALI = 1025
/**
* 支付类型
* 1余额,2三方支付,3混合
*/
private const val MONEY_TYPE_CHANGE = 1
private const val MONEY_TYPE_THIRD_PAY = 2
private const val MONEY_TYPE_MIXED = 3
}
init {
initView()
}
private fun initView() {
orientation = VERTICAL
val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
layoutParams = params
View.inflate(context, R.layout.view_pay_info_detail, this)
rl_discount.setOnClickListener {
listener.selectCoupon("")
}
tv_change_money.setOnClickListener {
if (isBalanceSufficient) {
isUseChange = true
} else {
isUseChange = !isUseChange
}
setChooseChangeMoney(isUseChange)
updateNeedPayMoney()
}
rl_weixin_pay.setOnClickListener {
if (isBalanceSufficient) {
isUseChange = false
setChooseChangeMoney(isUseChange)
updateNeedPayMoney()
}
setSelectPayWay(PAY_WECHAT)
}
rl_ali_pay.setOnClickListener {
if (isBalanceSufficient) {
isUseChange = false
setChooseChangeMoney(isUseChange)
updateNeedPayMoney()
}
setSelectPayWay(PAY_ALI)
}
tv_ensure_pay.setOnClickListener {
useMoneyType = if (!isUseChange) {
MONEY_TYPE_THIRD_PAY
} else if (isUseChange && sdkPayMoney > 0) {
MONEY_TYPE_MIXED
} else {
MONEY_TYPE_CHANGE
}
if (orderInfoBean!!.maxCoupon != null) {
listener.ensurePay(payWay, sdkPayMoney, useMoneyType, orderInfoBean!!.maxCoupon.code, orderInfoBean!!.maxCoupon.couponType)
} else {
listener.ensurePay(payWay, sdkPayMoney, useMoneyType, "", "")
}
}
}
fun setAvailableCount(availableCount: Int) {
this.availableCount = availableCount
}
/**
* 订单的信息
* @param payBusinessType 业务类型
*/
@SuppressLint("SetTextI18n")
fun setData(orderInfoBean: OrderInfoBean, payBusinessType: Int) {
this.orderInfoBean = orderInfoBean
if (payBusinessType == 1) {
tv_pay_title.text = "课程服务"
}
if (payBusinessType == 2) {
tv_pay_title.text = "倾诉服务"
}
if (payBusinessType == 3) {
tv_pay_title.text = "测评服务"
}
if (payBusinessType == 4) {
tv_pay_title.text = "咨询服务"
}
//价格
tv_price.text = orderInfoBean.applyFee.toString()
//可用余额
tv_change_useful.text = "[可用¥${orderInfoBean.availableMoney}]"
rl_discount.visibility = if (orderInfoBean.isShowCoupon) View.VISIBLE else View.GONE
setCouponData(orderInfoBean.maxCoupon)
}
/**
* 设置优惠券的数据
*
*/
@SuppressLint("SetTextI18n")
fun setCouponData(commonCouponBean: CommonCouponBean?) {
if (commonCouponBean == null) {
tv_discount_money.text = "0"
tv_flag.visibility = View.GONE
tv_discount_money.visibility = View.GONE
tv_no_choose.visibility = View.VISIBLE
if (availableCount == 0) {
tv_no_choose.text = "暂无优惠"
} else {
tv_no_choose.text = "有${availableCount}张优惠券可用"
}
orderInfoBean!!.maxCoupon = null
} else {
tv_flag.visibility = View.VISIBLE
tv_discount_money.visibility = View.VISIBLE
tv_no_choose.visibility = View.GONE
orderInfoBean!!.maxCoupon = commonCouponBean
//优惠
tv_discount_money.text = commonCouponBean.combinedAmount.toString()
}
updateNeedPayMoney()
}
/**
* 更新还需支付的金额
*/
private fun updateNeedPayMoney() {
var needPay = if (orderInfoBean!!.maxCoupon == null) {
orderInfoBean!!.applyFee
} else {
val b1 = BigDecimal(orderInfoBean!!.applyFee.toString())
val b2 = BigDecimal(orderInfoBean!!.maxCoupon.combinedAmount.toString())
b1.subtract(b2).toFloat()
}
if (needPay == 0f) {//优惠券已经完全抵扣
ll_third_pay.visibility = View.GONE
view_empty.visibility = View.VISIBLE
ll_third_pay.isEnabled = false
} else {//不能完全抵扣
ll_third_pay.visibility = View.VISIBLE
view_empty.visibility = View.GONE
ll_third_pay.isEnabled = true
}
if (isUseChange) {//使用余额
if (orderInfoBean!!.availableMoney >= needPay) {
tv_change_money.text = needPay.toString()
sdkPayMoney = 0f
setSelectPayWay(0)
isBalanceSufficient = true
} else {
tv_change_money.text = orderInfoBean!!.availableMoney.toString()
val bd1 = BigDecimal(needPay.toString())
val bd2 = BigDecimal(orderInfoBean!!.availableMoney.toString())
sdkPayMoney = bd1.subtract(bd2).toFloat()
// sdkPayMoney = needPay - orderInfoBean!!.availableMoney
if (payWay == 0) {
setSelectPayWay(PAY_WECHAT)
}
isBalanceSufficient = false
}
} else {//不使用余额
sdkPayMoney = needPay
}
// val bg = BigDecimal(sdkPayMoney.toDouble()).setScale(2, RoundingMode.UP)
tv_pay_money.text = sdkPayMoney.toString()
}
/**
* 选择支付方式
*/
private fun setSelectPayWay(way: Int) {
if (payWay == way) {
return
}
payWay = way
when (payWay) {
PAY_WECHAT -> {//微信
img_weixin_way.setImageResource(R.drawable.img_select)
img_ali_way.setImageResource(R.drawable.img_no_select)
}
PAY_ALI -> {//支付宝
img_weixin_way.setImageResource(R.drawable.img_no_select)
img_ali_way.setImageResource(R.drawable.img_select)
}
else -> {
img_ali_way.setImageResource(R.drawable.img_no_select)
img_weixin_way.setImageResource(R.drawable.img_no_select)
}
}
}
/**
* 是否选使用余额
*/
private fun setChooseChangeMoney(isUse: Boolean) {
if (isUse) {
tv_change_money.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.img_select, 0)
} else {
tv_change_money.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.img_no_select, 0)
}
}
interface OnCouponDetailClickListener {
/**
* 选择优惠券
*/
fun selectCoupon(couponId: String)
/**
* 确认支付
* @param payWay 支付方式 1024.微信支付 1025.支付宝支付
* @param payMoney 还需支付金额
* @param useMoneyType 支付类型 1余额,2三方支付,3混合
* @param code 优惠券code
* @param couponType 券类型 1兑换券 2新优惠券
*
*/
fun ensurePay(payWay: Int, payMoney: Float, useMoneyType: Int, code: String, couponType: String)
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_F3F3F3" />
<corners android:radius="20dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_FFFFFF" />
<corners
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"
android:topLeftRadius="10dp"
android:topRightRadius="10dp" />
</shape>
\ 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:state_enabled="false">
<shape>
<corners android:radius="15dp" />
<solid android:color="@color/color_CCCCCC" />
</shape>
</item>
<item android:state_enabled="true">
<shape>
<corners android:radius="15dp" />
<solid android:color="@color/color_FF6666" />
</shape>
</item>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00000000"
android:gravity="bottom">
<RelativeLayout
android:id="@+id/progress_layout"
android:layout_width="match_parent"
android:layout_height="411dp"
android:background="@drawable/background_common_pay_dialog">
<!--<ProgressBar-->
<!--android:id="@+id/progress"-->
<!--style="?android:attr/progressBarStyleSmall"-->
<!--android:indeterminateTint="@color/color_3D9EFF"-->
<!--android:indeterminateTintMode="src_atop"-->
<!--android:layout_width="32dp"-->
<!--android:layout_height="32dp"-->
<!--android:layout_centerInParent="true" />-->
</RelativeLayout>
<com.yidianling.ydl_pay.widget.NoScrollViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="425dp"
android:background="@drawable/background_common_pay_dialog"
android:visibility="gone"/>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rl_course"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="21dp"
android:layout_marginRight="15dp"
android:orientation="vertical">
<!-- 课程兑换码-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="课程兑换券码"
android:textColor="@color/color_3D3D3D"
android:textSize="15sp"
android:textStyle="bold" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:background="@drawable/background_choose_coupon">
<EditText
android:id="@+id/rt_coupon_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
android:layout_toLeftOf="@+id/tv_ensure"
android:background="@null"
android:digits="1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"
android:hint="请输入课程兑换券码"
android:textColor="@color/color_242424"
android:textColorHint="@color/color_999999"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_ensure"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="5dp"
android:background="@drawable/background_coupon_ensure_button"
android:enabled="false"
android:gravity="center"
android:paddingLeft="13dp"
android:paddingRight="12dp"
android:text="确认"
android:textColor="@color/color_FFFFFF"
android:textSize="15sp"
tools:enabled="true"
tools:text="取消使用" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:paddingTop="20dp"
android:paddingRight="15dp"
android:paddingBottom="10dp"
android:textColor="@color/color_3D3D3D"
android:textSize="15dp"
android:textStyle="bold" />
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="24dp">
<ProgressBar
style="?android:attr/progressBarStyleSmall"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_centerInParent="true"
android:layout_gravity="center" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="8dp">
<ImageView
android:id="@+id/iv_background"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@drawable/item_coupon_background" />
<LinearLayout
android:id="@+id/ll_background"
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="114"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lineSpacingExtra="0dp"
android:textColor="@color/color_FFFFFF"
android:textSize="25sp"
tools:text="¥100" />
<TextView
android:id="@+id/tv_discountCont"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/color_FFFFFF"
android:textSize="14sp"
android:visibility="gone"
tools:text="满50元可用" />
</LinearLayout>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="231"
android:paddingLeft="12dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginTop="15dp"
android:layout_marginRight="10dp"
android:layout_toLeftOf="@+id/iv_select"
android:text="咨询优惠券"
android:textColor="@color/color_242424"
android:textSize="16dp"
tools:text="咨询优咨咨询优咨询优惠券惠券询优惠券惠券"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_title"
android:layout_marginTop="3dp"
android:textColor="@color/color_242424"
android:textSize="11sp"
tools:text="有效期至2018-08-31" />
<TextView
android:id="@+id/tv_use_condition"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="11dp"
android:text="使用规则"
android:textColor="@color/color_666666"
android:textSize="10sp" />
<ImageView
android:id="@+id/iv_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginTop="18dp"
android:layout_marginRight="12dp"
android:src="@drawable/img_no_select" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
\ No newline at end of file
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