| @@ -241,6 +241,9 @@ | |||
| <entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/fragment_statistics_time_top.xml" value="0.23385416666666667" /> | |||
| <entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/item_statics_for_time.xml" value="0.24791666666666667" /> | |||
| <entry key="..\:/xuekaole/XKLLocal/lib/common/src/main/res/drawable/ic_search.xml" value="0.2212962962962963" /> | |||
| <entry key="..\:/xuekaole/XKLLocal/videoplayer/src/main/res/layout/pine_player_media_controller.xml" value="0.125" /> | |||
| <entry key="..\:/xuekaole/XKLLocal/videoplayer/src/main/res/layout/pine_player_media_controller_full.xml" value="0.125" /> | |||
| <entry key="..\:/xuekaole/XKLLocal/videoplayer/src/main/res/layout/video_popup.xml" value="0.1953125" /> | |||
| </map> | |||
| </option> | |||
| </component> | |||
| @@ -89,10 +89,10 @@ dependencies { | |||
| implementation fileTree(include: ['*.jar', "*.aar"], dir: 'libs') | |||
| // implementation 'androidx.legacy:legacy-support-v4:1.0.0' | |||
| implementation project(path: ':lib:common') | |||
| implementation project(path: ':videoplayer') | |||
| implementation 'androidx.appcompat:appcompat:1.2.0' | |||
| implementation 'com.google.android.material:material:1.3.0' | |||
| implementation 'androidx.constraintlayout:constraintlayout:2.0.4' | |||
| implementation project(path: ':videoplayer') | |||
| // implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1' | |||
| // implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' | |||
| // implementation 'androidx.appcompat:appcompat:1.2.0' | |||
| @@ -711,7 +711,8 @@ object DBCourseManager { | |||
| while (moveToNext()) { | |||
| val videoAnchor = VideoAnchor().apply { | |||
| anchor_id = getLong(3) | |||
| title = getString(5) | |||
| // TODO: 2022/8/24 需要确定数据库打包是否错误,没有错误用4,有错误用5 | |||
| title = getString(4) | |||
| time = DateUtil.getTimeSecond(getString(2)) | |||
| } | |||
| videoAnchorList.add(videoAnchor) | |||
| @@ -48,17 +48,24 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
| if (vm.course.courseType == AppConstants.COURSE_TYPE_ENGLISH_SPOKEN) { | |||
| binding.spokenTopLayout.visibility = View.VISIBLE | |||
| } | |||
| val selectPos = vm.initSelectPosition() | |||
| binding.recyclerView.apply { | |||
| layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false) | |||
| adapterLesson = AdapterLesson(vm).apply { | |||
| onItemClick = onLessonClick | |||
| //默认选中位置,默认为0 ,如果学习完成则设置为-1 | |||
| selectPos = vm.initSelectPosition() | |||
| this.selectPos = selectPos | |||
| } | |||
| adapter = adapterLesson | |||
| } | |||
| //设置数据 | |||
| (binding.recyclerView.adapter as AdapterLesson).setData(vm.allLesson.toMutableList()) | |||
| //滑动到学习的位置 | |||
| if (selectPos != -1){ | |||
| binding.recyclerView.post { | |||
| binding.recyclerView.smoothScrollToPosition(selectPos) | |||
| } | |||
| } | |||
| } | |||
| override fun loadData() { | |||
| @@ -70,14 +70,22 @@ class MemoTestViewModel : BaseViewModel() { | |||
| } | |||
| } | |||
| /** 查询课程的所有课时 */ | |||
| /** 查询课程的所有课时 ,作文显示章节,故只使用了知识点学习所在的课时*/ | |||
| fun queryAllLesson() { | |||
| if (isAllLessonListInit()) { | |||
| showLessonListLivaData.value = 2 | |||
| } else { | |||
| DataRepository.getCourseAllLesson(dbControlBase, CourseDetail()).compose(diskIo2Main()).subscribe({ | |||
| allLessonList = it.toMutableList() | |||
| //如果是作文,取知识点的所在的章节即可 | |||
| if (memoData.course.coursePackType == AppConstants.COURSEPACK_TYPE_CHINESE_COMPOSITION){ | |||
| allLessonList = it.filter { | |||
| it.lessonType == AppConstants.LESSON_TYPE_COMPOSITION_KNOWLEDGE | |||
| }.toMutableList() | |||
| } else { | |||
| allLessonList = it.toMutableList() | |||
| } | |||
| showLessonListLivaData.value = 2 | |||
| }, { | |||
| it.printStackTrace() | |||
| }) | |||
| @@ -120,9 +128,8 @@ class MemoTestViewModel : BaseViewModel() { | |||
| //查询测试数据 | |||
| val testDataList = DBCourseManager.queryMemoTest(dbControlBase, queryLesson, count) | |||
| //测试类型 | |||
| val examType = if (recordTestType == 1) AppConstants.TEST_TYPE_MEMO else AppConstants.TEST_TYPE_SERVICE_CENTER | |||
| return@fromCallable ExamData(memoData.course.subjectId, examType, memoData.course.courseTitle, | |||
| saveTitle).apply { | |||
| val examType = if (recordTestType == 1) AppConstants.TEST_TYPE_MEMO else AppConstants.TEST_TYPE_SERVICE_CENTER | |||
| return@fromCallable ExamData(memoData.course.subjectId, examType, memoData.course.courseTitle, saveTitle).apply { | |||
| coursePackId = memoData.course.coursePackId //课程包id, 测试错误上次数据需要 | |||
| coursePackType = memoData.course.coursePackType //课程包类型 | |||
| courseId = memoData.course.courseId //课程id | |||
| @@ -267,7 +267,7 @@ open class StatisticsTimeTopFragmentViewModel : BaseViewModel() { | |||
| } | |||
| } | |||
| /**实例化增量图标和颜色与正负*/ | |||
| /**实例化增量图标和颜色*/ | |||
| private fun initIncr(timeStaticItem_1 : TimeStatisticItem, sdIncr : Double) { | |||
| timeStaticItem_1.run { | |||
| when{ | |||
| @@ -337,12 +337,12 @@ class LearnRuleUtil<T : BaseWord> constructor(private val originLearnList : List | |||
| * @return true在 false不存在 | |||
| */ | |||
| fun isInExamErrorMap(key : String) : Boolean { | |||
| return examErrorsMap?.getOrDefault(key, false) ?: false | |||
| return examErrorsMap?.containsKey(key) ?: false | |||
| } | |||
| /** 是否是在学习的错误列表中 */ | |||
| fun isInCurrentErrorMap(key : String) : Boolean { | |||
| return currentErrorMap.getOrDefault(key, false) | |||
| return currentErrorMap.containsKey(key) | |||
| } | |||
| /** 判断源数据中的数据是否已经学习完成:由外部调用,originLearnPosition下标的数据为已经取出来学习的数据,只有为第一个的时候,才判断此方法 */ | |||
| @@ -6,7 +6,8 @@ | |||
| # http://www.gradle.org/docs/current/userguide/build_environment.html | |||
| # Specifies the JVM arguments used for the daemon process. | |||
| # The setting is particularly useful for tweaking memory settings. | |||
| org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 | |||
| #org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 | |||
| org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 | |||
| # When configured, Gradle will run in incubating parallel mode. | |||
| # This option should only be used with decoupled projects. More details, visit | |||
| # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects | |||
| @@ -12,4 +12,4 @@ dependencyResolutionManagement { | |||
| rootProject.name = "XklLocal" | |||
| include ':app' | |||
| include ':lib:common' | |||
| include ':videoplayer' | |||
| include 'videoplayer' | |||
| @@ -1,6 +1,6 @@ | |||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | |||
| package="com.xkl.videoplayer" > | |||
| <!-- <uses-permission android:name="android.permission.WRITE_SETTINGS" />--> | |||
| <!-- <uses-permission android:name="android.permission.WRITE_SETTINGS" />--> | |||
| <application | |||
| android:allowBackup="true" | |||
| android:label="@string/app_name" | |||
| @@ -1,4 +1,11 @@ | |||
| cmake_minimum_required(VERSION 3.4.1) | |||
| #if (${ANDROID_ABI} STREQUAL "armeabi-v7a") | |||
| # include_directories(${ANDROID_SYSROOT}/usr/include/arm-linux-androideabi) | |||
| #elseif (${ANDROID_ABI} STREQUAL "arm64-v8a") | |||
| # include_directories(${ANDROID_SYSROOT}/usr/include/aarch64-linux-android) | |||
| #else () | |||
| # include_directories(${ANDROID_SYSROOT}/usr/include/arm-linux-androideabi) | |||
| #endif () | |||
| find_library( | |||
| log-lib | |||
| @@ -64,6 +71,16 @@ PROPERTIES IMPORTED_LOCATION ../../../../libs/${ANDROID_ABI}/libavfilter.so | |||
| ) | |||
| #add_library( | |||
| # postproc | |||
| # SHARED | |||
| # IMPORTED | |||
| #) | |||
| #set_target_properties(postproc | |||
| #PROPERTIES IMPORTED_LOCATION ../../../../libs/${ANDROID_ABI}/lipostproc.so | |||
| #) | |||
| target_link_libraries(MoviePlayer | |||
| avutil | |||
| @@ -205,7 +205,7 @@ public class MoviePlayer { | |||
| private long previousPlayTime; //播放上一次记录的时间 | |||
| public void PlayPCM(byte[] pcmBuffer, int length, int milliseconds) { | |||
| // LogUtil.e("MoviePlayer", "PlayPCM milliseconds = " + milliseconds + " Length=" + length ); | |||
| // LogUtil.INSTANCE.e("MoviePlayer", "PlayPCM milliseconds = " + milliseconds + " Length=" + length ); | |||
| if (null != audioTrack && AudioTrack.PLAYSTATE_PLAYING == audioTrack.getPlayState()) { | |||
| audioTrack.write(pcmBuffer, 0, length); | |||
| currentPosition = milliseconds; | |||
| @@ -231,7 +231,7 @@ public class MoviePlayer { | |||
| if (l - l1 > 3000) { //误差超过三秒降帧 | |||
| previousPlayTime = 0; | |||
| LogUtil.INSTANCE.e("MoviePlayer localTimeInterval = " + l + " playIntervelTime = " + l1); | |||
| LogUtil.INSTANCE.e("MoviePlayer", "localTimeInterval = " + l + " playIntervelTime = " + l1); | |||
| if (onPlayStatusChanged != null) { | |||
| onPlayStatusChanged.onStatus(10); | |||
| } | |||
| @@ -17,7 +17,6 @@ import java.util.List; | |||
| /** | |||
| * Created by tanghongfeng on 2017/9/18. | |||
| * 要播放的多媒体的 | |||
| */ | |||
| /** | |||
| @@ -9,7 +9,6 @@ import java.util.ArrayList; | |||
| /** | |||
| * Created by tanghongfeng on 2018/3/7. | |||
| * 要播放的多媒体的数据源的实体类 | |||
| */ | |||
| public class PineMediaUriSource implements Serializable { | |||
| @@ -42,7 +42,6 @@ import static com.xkl.videoplayer.component.PinePlayState.STATE_PREPARING; | |||
| /** | |||
| * 播放器组件,封装播放器细节 | |||
| * 封装具体的播放器,通过代理PineMediaPlayerProxy与界面进行交互 | |||
| * Created by tanghongfeng on 2017/8/14. | |||
| */ | |||
| @@ -714,10 +713,15 @@ public class PineMediaPlayerComponent implements PineMediaWidget.IPineMediaPlaye | |||
| LogUtil.INSTANCE.e("=================>", "状态:" + "JPlayer"); | |||
| isSwitchDefinition = false; | |||
| moviePlayer.JPlay(); | |||
| if (moviePlayer.getCachPosition() != 0) { | |||
| LogUtil.INSTANCE.e("=================>", "状态:" + "SetPlayTime:" + moviePlayer.getCachPosition()); | |||
| moviePlayer.SetPlayTime(moviePlayer.getCachPosition()); | |||
| moviePlayer.setCachPosition(0); | |||
| // if (moviePlayer.getCachPosition() != 0) { | |||
| // LogUtil.INSTANCE.e("=================>", "状态:" + "SetPlayTime:" + moviePlayer.getCachPosition()); | |||
| // moviePlayer.SetPlayTime(moviePlayer.getCachPosition()); | |||
| // moviePlayer.setCachPosition(0); | |||
| // } | |||
| if (getCachPositon() != 0) { | |||
| LogUtil.INSTANCE.e("=================>", "状态:" + "SetPlayTime:" + getCachPositon()); | |||
| moviePlayer.SetPlayTime(getCachPositon()); | |||
| setCachPosition(0); | |||
| } | |||
| } else { | |||
| LogUtil.INSTANCE.e("=================>", "状态:" + "JResume:"); | |||
| @@ -861,13 +865,20 @@ public class PineMediaPlayerComponent implements PineMediaWidget.IPineMediaPlaye | |||
| moviePlayer.setCurrentPosition(position); | |||
| } | |||
| } | |||
| private int chachePosition = 0 ; | |||
| public void setCachPosition(int position) { | |||
| if (moviePlayer == null){ | |||
| chachePosition = position ; | |||
| return; | |||
| } | |||
| moviePlayer.setCachPosition(position); | |||
| } | |||
| @Override | |||
| public int getCachPositon() { | |||
| if (moviePlayer == null){ | |||
| return chachePosition; | |||
| } | |||
| return moviePlayer.getCachPosition(); | |||
| } | |||
| @@ -13,7 +13,6 @@ import java.util.Map; | |||
| /** | |||
| * Created by tanghongfeng on 2018/4/2. | |||
| * 播放器组件代理类 | |||
| */ | |||
| public class PineMediaPlayerProxy implements PineMediaWidget.IPineMediaPlayer, PineMediaWidget.IPineMediaPlayerComponent { | |||
| @@ -12,7 +12,6 @@ import java.util.Map; | |||
| /** | |||
| * Created by tanghongfeng on 2017/8/28. | |||
| * 播放器组件接口集合 | |||
| */ | |||
| public class PineMediaWidget { | |||
| @@ -1065,7 +1065,7 @@ public class PineMediaController extends RelativeLayout implements PineMediaWidg | |||
| mWaitingProgressViewHolder = new PineWaitingProgressViewHolder(); | |||
| } | |||
| // 内置右侧Views | |||
| // LogUtil.INSTANCE.e("attachToParentView",mRightViewHolderList.toString()); | |||
| LogUtil.INSTANCE.e("attachToParentView",mRightViewHolderList.toString()); | |||
| if (mRightViewHolderList != null && mRightViewHolderList.size() > 0) { | |||
| mRightViewContainer = new RelativeLayout(getContext()); | |||
| for (int i = 0; i < mRightViewHolderList.size(); i++) { | |||
| @@ -163,14 +163,14 @@ public class DefaultVideoControllerAdapter extends PineMediaController.AbstractM | |||
| mediaListBtn.setVisibility(View.GONE); | |||
| } | |||
| mDDefinitionBtn = (TextView) mDFullControllerView.findViewById(R.id.media_definition_text); | |||
| PineMediaPlayerBean pineMediaPlayerBean = player.getMediaPlayerBean(); | |||
| if (hasDefinitionList(pineMediaPlayerBean) && mDEnableDefinition) { | |||
| rightViewControlBtnList.add(mDDefinitionBtn); | |||
| mDDefinitionBtn.setVisibility(View.VISIBLE); | |||
| mDDefinitionBtn.setText(getDefinitionName(pineMediaPlayerBean.getCurrentDefinition())); | |||
| } else { | |||
| // PineMediaPlayerBean pineMediaPlayerBean = player.getMediaPlayerBean(); | |||
| // if (hasDefinitionList(pineMediaPlayerBean) && mDEnableDefinition) { | |||
| // rightViewControlBtnList.add(mDDefinitionBtn); | |||
| // mDDefinitionBtn.setVisibility(View.VISIBLE); | |||
| // mDDefinitionBtn.setText(getDefinitionName(pineMediaPlayerBean.getCurrentDefinition())); | |||
| // } else { | |||
| mDDefinitionBtn.setVisibility(View.GONE); | |||
| } | |||
| // } | |||
| if (rightViewControlBtnList.size() > 0) { | |||
| mDFullControllerViewHolder.setRightViewControlBtnList(rightViewControlBtnList); | |||
| } | |||
| @@ -406,7 +406,8 @@ public class DefaultVideoControllerAdapter extends PineMediaController.AbstractM | |||
| } | |||
| private boolean hasDefinitionList(PineMediaPlayerBean pineMediaPlayerBean) { | |||
| return pineMediaPlayerBean != null && pineMediaPlayerBean.getMediaUriSourceList().size() > 1; | |||
| return pineMediaPlayerBean != null; | |||
| // && pineMediaPlayerBean.getMediaUriSourceList().size() > 1; | |||
| } | |||
| public String getCurMediaCode() { | |||
| @@ -202,7 +202,8 @@ | |||
| android:layout_centerVertical="true" | |||
| android:textSize="14sp" | |||
| android:text="@string/pine_media_definition_sd" | |||
| android:textColor="@color/pine_controller_text"/> | |||
| android:textColor="@color/pine_controller_text" | |||
| android:visibility="gone"/> | |||
| <ImageView | |||
| android:id="@+id/full_screen_btn" | |||