package com.nsmss.scuol.course; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import com.nsmss.scuol.R; import com.nsmss.scuol.bean.CourseData; import com.nsmss.scuol.bean.CourseInfo; import com.nsmss.scuol.bean.GlobalInfo; import com.nsmss.scuol.bean.UserData; import com.nsmss.scuol.common.MyFragmentPagerAdapter; import com.nsmss.scuol.common.NetHelper; import com.nsmss.scuol.common.Utility; import com.nsmss.scuol.course.CourseFragment.CourseListAdapter; import com.nsmss.scuol.course.CourseFragment.CourseListInfo; import com.nsmss.scuol.dao.CourseDataDao; import com.nsmss.scuol.dao.CourseInfoDao; import com.nsmss.scuol.dao.GlobalInfoDao; import com.nsmss.scuol.dao.UserDataDao; import com.nsmss.scuol.main.MainActivity; import android.annotation.SuppressLint; import android.app.ProgressDialog; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.view.KeyEvent; import android.view.View; import android.view.animation.Animation; import android.view.animation.TranslateAnimation; import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; /** * @author LMD * OnCreate步骤: * 1. 从数据库读取课程数据链表 * 2. 将课程信息按照俄罗斯方块法存入课程链表的二维数组 (putCourse) * 3. 记录当前激活状态的二维数组初始化(initActive) * 4. 提取激活的课程进行处理 (processCourse) * 5. 处理后的课程添加到fragmentList * * 刷新步骤: * 1. 从NetHelper获取课程数据链表 * 2. 存入数据库 * 3. putCourse * 4. initActive * 5. processCourse * 6. 更新fragmentList * 7. 刷新ListView * * 切换重叠课程步骤: * 1. 更新激活状态数组 * 2. processCourse * 3. 更新fragmentList * 4. notify */ public class CourseActivity extends FragmentActivity { /** * 静态成员变量 */ private static Context context; private Resources resources; // 每天的课程数 private final int dayCourseNum = 12; // 每天的课程分布(即大节间的分割是第几小节) private final int courseDistribution[] = {2, 4, 6, 9, 12}; // 激活课程状态 private int activeCourse[][]; /** * UI相关成员变量 */ private ProgressDialog progressDialog; private MyFragmentPagerAdapter myAdapter; private ViewPager mPager; /** * View相关成员变量 */ private View backView; private View refreshView; private ImageView ivBottomLine; private TextView weekDaysTextView[]; private View positionView1; /** * Dao成员变量 */ GlobalInfoDao gDao; UserDataDao uDao; CourseInfoDao cInfoDao; CourseDataDao cDataDao; /** * 数据模型变量 */ GlobalInfo gInfo; UserData uData; /** * 数据存储变量 */ private ArrayList<Fragment> fragmentsList; private LinkedList<CourseInfo> courseInfoList; //课程信息链表 ArrayList<ArrayList<LinkedList<CourseInfo>>> weekCourse; /** * 状态变量 */ private boolean is_first = true; /** * 临时变量 */ private NetHelper nHelper; private int uid; private int currIndex; private int currentWeek; private int position[]; private int offset; /** * Activity回调函数 */ @Override protected void onCreate(Bundle savedInstanceState) { // 继承父类方法,绑定View super.onCreate(savedInstanceState); setContentView(R.layout.activity_course); // 初始化context context = getApplicationContext(); resources = getResources(); // 初始化View成员变量 // 初始化Dao成员变量 gDao = new GlobalInfoDao(context); uDao = new UserDataDao(context); cInfoDao = new CourseInfoDao(context); cDataDao = new CourseDataDao(context); // 初始化数据模型变量 gInfo = gDao.query(); uid = gInfo.getActiveUserUid(); uData = uDao.query(uid); // 初始化状态变量 // 初始化临时变量 nHelper = new NetHelper(); currentWeek = Utility.getWeeks(gInfo.getTermBegin()); position = new int[7]; offset = 0; // 自定义函数 initDay(); initView(); initListener(); } @Override public void onWindowFocusChanged(boolean hasFocus) { if (hasFocus && is_first) { initWidth(); is_first = false; } } @Override protected void onPause() { super.onPause(); } @Override protected void onStop() { super.onStop(); } @Override protected void onResume() { super.onResume(); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) { jumpToMain(); return true; } return super.onKeyDown(keyCode, event); } /** * 线程对象 */ private Runnable connRunnable = new Runnable() { @Override public void run() { courseInfoList = nHelper.getCourse(uData); // 如果连接成功,返回了更新数据 if (courseInfoList != null) { // 判断状态对话框是否显示 if (progressDialog.isShowing()) { if (saveCourse()) { fragmentsList.clear(); initCourse(); initActive(); putCourse(); processCourse(); progressDialog.dismiss(); runOnUiThread(succRunnable); } else { progressDialog.dismiss(); runOnUiThread(errURunnable); } } } // 连接错误 else { // 判断状态对话框是否显示 if (progressDialog.isShowing()) { progressDialog.dismiss(); runOnUiThread(errRunnable); } } } }; // 连接成功线程 private Runnable succRunnable = new Runnable() { @Override public void run() { // TODO 更新显示 myAdapter.notifyDataSetChanged(); Toast.makeText(CourseActivity.this, "更新成功", Toast.LENGTH_SHORT).show(); } }; // 连接错误线程 private Runnable errRunnable = new Runnable() { @Override public void run() { Toast.makeText(CourseActivity.this, "连接错误!请检查网络连接!", Toast.LENGTH_SHORT).show(); } }; // 更新错误线程 private Runnable errURunnable = new Runnable() { @Override public void run() { Toast.makeText(CourseActivity.this, "更新错误!", Toast.LENGTH_SHORT).show(); } }; /** * 自定义成员对象 */ @SuppressLint("HandlerLeak") public class MyOnClickListener implements View.OnClickListener { private int index = currIndex; public MyOnClickListener(int i) { index = i; } @Override public void onClick(View v) { mPager.setCurrentItem(index); } }; public class MyOnPageChangeListener implements OnPageChangeListener { @Override public void onPageSelected(int arg0) { Animation animation = null; // 将之前的高亮颜色恢复 animation = new TranslateAnimation(position[currIndex], position[arg0], 0, 0); weekDaysTextView[currIndex].setTextColor(resources.getColor(R.color.scu__defaultSubHeadText)); // 高亮选中的文字 weekDaysTextView[arg0].setTextColor(resources.getColor(R.color.scu__defaultMianTitle)); // 滑块动画移动 animation.setFillAfter(true); animation.setDuration(300); ivBottomLine.startAnimation(animation); // 设置Current currIndex = arg0; } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageScrollStateChanged(int arg0) { } } /** * 自定义方法 */ private void initDay() { Date date = new Date(); Calendar cal = Calendar.getInstance(); cal.setFirstDayOfWeek(Calendar.MONDAY); cal.setTime(date); int dayOfWeek =cal.get(Calendar.DAY_OF_WEEK); if (dayOfWeek == 1) { currIndex = 6; } else { currIndex = dayOfWeek-2; } } private void initView() { backView = findViewById(R.id.Btn_Course_Back); refreshView = findViewById(R.id.Btn_Course_Refresh); ivBottomLine = (ImageView) findViewById(R.id.Img_Course_Subhead_Line); weekDaysTextView = new TextView[7]; weekDaysTextView[0] = (TextView) findViewById(R.id.Text_Course_Subhead_Mon); weekDaysTextView[1] = (TextView) findViewById(R.id.Text_Course_Subhead_Tue); weekDaysTextView[2] = (TextView) findViewById(R.id.Text_Course_Subhead_Wed); weekDaysTextView[3] = (TextView) findViewById(R.id.Text_Course_Subhead_Thu); weekDaysTextView[4] = (TextView) findViewById(R.id.Text_Course_Subhead_Fri); weekDaysTextView[5] = (TextView) findViewById(R.id.Text_Course_Subhead_Sat); weekDaysTextView[6] = (TextView) findViewById(R.id.Text_Course_Subhead_Sun); weekDaysTextView[currIndex].setTextColor(resources.getColor(R.color.scu__defaultMianTitle)); positionView1 = findViewById(R.id.View_Course_Position_1); mPager = (ViewPager) findViewById(R.id.Pager_Course_Content); fragmentsList = new ArrayList<Fragment>(); // TODO 显示课表 courseInfoList = cDataDao.query(uid); initCourse(); initActive(); putCourse(); processCourse(); myAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), fragmentsList); mPager.setAdapter(myAdapter); mPager.setCurrentItem(currIndex); mPager.setOnPageChangeListener(new MyOnPageChangeListener()); } private void initListener() { backView.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { jumpToMain(); } }); refreshView.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { refresh(); } }); for (int i = 0; i < 7; i++) { weekDaysTextView[i].setOnClickListener(new MyOnClickListener(i)); } } private void initWidth() { View wraper1 = findViewById(R.id.View_Course_SubWrap_1); View wraper2 = findViewById(R.id.View_Course_SubWrap_2); int left = positionView1.getLeft(); int pos1 = wraper1.getLeft(); int pos2 = wraper2.getLeft(); offset = pos2-pos1; LinearLayout.LayoutParams lineParams = (LinearLayout.LayoutParams) ivBottomLine.getLayoutParams(); lineParams.width = positionView1.getRight()-left; ivBottomLine.setLayoutParams(lineParams); for (int i = 0; i < 7; i++) { position[i] = left+offset*i; } // 设置滑块初始位置 Animation animation = new TranslateAnimation(0, position[currIndex], 0, 0); animation.setFillAfter(true); animation.setDuration(0); ivBottomLine.startAnimation(animation); } private void jumpToMain() { Intent intent=new Intent(); intent.setClass(CourseActivity.this, MainActivity.class); startActivity(intent); overridePendingTransition(R.anim.slide_left_in, R.anim.slide_right_out); finish(); } private void refresh() { // 显示状态对话框 progressDialog = new ProgressDialog(this); progressDialog.setIndeterminate(true); progressDialog.setMessage(getResources().getString(R.string.loading_tip)); progressDialog.setCancelable(true); progressDialog.show(); // 开启连接线程 new Thread(connRunnable).start(); } /** * 将课程列表存入数据库 * @param cList * @return */ private boolean saveCourse() { if (cDataDao.clear(uid)) { for (CourseInfo cInfo : courseInfoList) { int cid = cInfoDao.insert(cInfo); if (cid == 0) { return false; } CourseData cData = new CourseData(); cData.setUid(uid); cData.setCid(cid); if(!cDataDao.insert(cData)) { return false; } } return true; } return false; } private void initCourse() { weekCourse = new ArrayList<ArrayList<LinkedList<CourseInfo>>>(7); for (int i = 0; i < 7; i++) { ArrayList<LinkedList<CourseInfo>> dayCourses = new ArrayList<LinkedList<CourseInfo>>(); for (int j = 0; j < dayCourseNum; j++) { LinkedList<CourseInfo> courseInfos = new LinkedList<CourseInfo>(); dayCourses.add(courseInfos); } weekCourse.add(dayCourses); } } /** * 初始化激活课程数组 */ private void initActive() { activeCourse = new int[7][dayCourseNum]; } /** * 使用俄罗斯方块法 * 将courseInfoList中的课程放入weekCourse中 */ private void putCourse() { for (CourseInfo courseInfo : courseInfoList) { int day = courseInfo.getDay(); int lessonFrom = courseInfo.getLessonfrom(); int lessonTo = courseInfo.getLessonto(); LinkedList<CourseInfo> tmpCouses = null; int maxSize = 0; int tmpSize = 0; for (int i = lessonFrom; i <= lessonTo; ) { maxSize = 0; // 每个j表示每个小节位置 int j = i; outer: for (; j <= lessonTo; j++) { tmpCouses = weekCourse.get(day-1).get(j-1); tmpSize = 0; // 如果课程链表中间有null(填充的空课程) // 如果最大的null的高度比maxSize大,maxSize提升到此高度 for (CourseInfo tmpCourse : tmpCouses) { tmpSize ++; if (tmpCourse == null) { if (tmpSize > maxSize) { maxSize = tmpSize; } } } // 如果课程链表中没有null // 则把链表的长度与maxSize比较 if (tmpSize == 0) { tmpSize = tmpCouses.size(); if (tmpSize > maxSize) { maxSize = tmpSize; } } for (int k = 0; k < courseDistribution.length; k++) { // j碰到了大节分隔的边界 // i和j之间的课程就是分隔出来的一段 if (j == courseDistribution[k] || j == lessonTo) { for (int l = i; l <= j; l++) { tmpCouses = weekCourse.get(day-1).get(l-1); tmpSize = tmpCouses.size(); // 添加到最后 if (maxSize == tmpSize) { tmpCouses.addLast(courseInfo); } // 添加到中间 else if (maxSize < tmpSize) { tmpCouses.set(maxSize-1, courseInfo); } // 添加到最后往后的几个,填充null else { for (int m = tmpSize; m < maxSize; m++) { tmpCouses.addLast(null); } tmpCouses.addLast(courseInfo); } } // 切换到下一个大节 i = j + 1; // 找到了最近的分割边界,不用再往后找了 break outer; } } } } } } private void processCourse() { NumberFormat formatter = NumberFormat.getNumberInstance(); formatter.setMinimumIntegerDigits(2); formatter.setGroupingUsed(false); for (int i = 0; i < 7; i++) { List<Map<String, String>> dayMaps = new ArrayList<Map<String, String>>(); for (int j = 0; j < dayCourseNum;) { /** * tmpMap的type属性: * 为"-1":表示当前课程和前面的相同,已被覆盖 * 为"0": 表示当前课程没有课 * 为"1": 表示有课 * 为"2": 表示午休 * 为"3": 表示晚饭 */ HashMap<String, String> tmpMap = new HashMap<String, String>(); LinkedList<CourseInfo> courseInfos = weekCourse.get(i).get(j); CourseInfo courseInfo = null; if (courseInfos.size() != 0 && activeCourse[i][j] < courseInfos.size()) { courseInfo = weekCourse.get(i).get(j).get(activeCourse[i][j]); } if (courseInfo == null) { tmpMap.put("type", "0"); tmpMap.put("lesson", formatter.format(j+1)); dayMaps.add(tmpMap); j++; } else { tmpMap.put("type", "1"); tmpMap.put("subject", courseInfo.getName()); tmpMap.put("attr", courseInfo.getAttr()); tmpMap.put("timefrom", Utility.campusTime(courseInfo.getCampus(), j+1, true)); tmpMap.put("place", "("+courseInfo.getCampus()+")"+courseInfo.getBld()+courseInfo.getPlace()); switch (courseInfo.getWeektype()) { case 1: if (courseInfo.getWeekfrom() == courseInfo.getWeekto()) { tmpMap.put("weeks", "第"+courseInfo.getWeekfrom()+"周"); } else { tmpMap.put("weeks", courseInfo.getWeekfrom()+"-"+courseInfo.getWeekto()+"周"); } break; case 2: tmpMap.put("weeks", "单周"); break; case 3: tmpMap.put("weeks", "双周"); break; default: tmpMap.put("weeks", ""); } // 往后找相同的课程合并到一起 int sameNum = 0; int k = j + 1; for (; k < courseInfo.getLessonto(); k++) { CourseInfo nextInfo = weekCourse.get(i).get(k).get(activeCourse[i][k]); // 如果是相同的课程 if ( nextInfo.getCourseid() == courseInfo.getCourseid() && nextInfo.getNum() == courseInfo.getNum() ) { sameNum ++; } else { break; } } if (sameNum > 0) { tmpMap.put("lesson", formatter.format(j+1)+"-"+formatter.format(j+sameNum+1)); tmpMap.put("timeto", Utility.campusTime(courseInfo.getCampus(), j+sameNum+1, false)); dayMaps.add(tmpMap); for (int l = 1; l <= sameNum; l++) { HashMap<String, String> tmpMapNext = new HashMap<String, String>(); tmpMapNext.put("type", "-1"); dayMaps.add(tmpMapNext); } } else { tmpMap.put("timeto", Utility.campusTime(courseInfo.getCampus(), j+1, false)); tmpMap.put("lesson", formatter.format(j+1)); dayMaps.add(tmpMap); } j = k; } } Map<String, String> tmpMap = new HashMap<String, String>(); tmpMap.put("type", "2"); dayMaps.add(4, tmpMap); tmpMap = new HashMap<String, String>(); tmpMap.put("type", "3"); dayMaps.add(10, tmpMap); Fragment courseFragment = CourseFragment.newInstance(dayMaps); fragmentsList.add(courseFragment); } } /** * 处理课程 */ /* private void processCourse() { // 先初始化一个Map的链表的二维数组表示一周每天每小节所以的课程信息 weekCourse = new ArrayList<ArrayList<LinkedList<CourseInfo>>>(7); for (int i = 0; i < 7; i++) { ArrayList<LinkedList<Map<String, Object>>> dayCourse = new ArrayList<LinkedList<Map<String, Object>>>(dayCourseNum); for (int j = 0; j < dayCourseNum; j++) { LinkedList<Map<String, Object>> lessonCourse = new LinkedList<Map<String, Object>>(); Map<String, Object> tmpMap = new HashMap<String, Object>(); /** * 方案一 * 链表的第一个元素用来指示当前小节位置的状态 * type为0:表示当前小节没有课程(将显示小节号,但没有课程信息) * type为-1:表示当前小节是处于某个大节的非开始小节(将不会显示) * type为1:表示当前小节是某个小节或者某个大节的第一小节(显示小节号或者大节的起始-终止小节,以及彩色显示的课程信息) * type为2:表示当前小节在当前周没有课程,但在其他周有课程(显示小节号或者大节的起始-终止小节,以及灰色显示的课程信息) */ /** * 方案二 * * 头节点 * 用"num"指示当前位置有几个课程(包括占位的), * 用"active"表示当前激活的是第几个(从1开始) * * 中间节点 * 用"dummy"(为1)表示当前位置是用来占位的(实际本小节没有课程但是当前大节中有某个小节有这个课程) */ /** * 方案三 * 俄罗斯方块法 * 将连续的课程看成长条的方块 * 按照大节分布切分成首尾相连的几个短一些的条 * 从上往下落,每个块都遵循俄罗斯方块的规则 * 即下落过程中每个方块只要在下方碰到了已有的方块就会停止下落 * 实际方向相反即从底部往上冒(因为小节课程是用链表存储,只能从下往上访问) * 使用一个变量来记录当前最高的高度+1,表示下次放课程的高度的最大值 */ /* tmpMap.put("num", 0); tmpMap.put("active", 0); lessonCourse.add(tmpMap); dayCourse.add(lessonCourse); } weekCourse.add(dayCourse); } for (CourseInfo cInfoTmp : courseInfoList) { int lessonFrom = cInfoTmp.getLessonfrom(); int lessonTo = cInfoTmp.getLessonto(); int lessons = lessonTo-lessonFrom; int day = cInfoTmp.getDay(); for (int i = lessonFrom; i <= lessonTo; ) { if (i == 1 || i == 3 || i == 5) { insertCourse(day, i, 0, cInfoTmp); } } if (lessonFrom == 1 || lessonFrom == 3 || lessonFrom == 5) { insertCourse(day, lessonFrom, 0, cInfoTmp); switch (lessons) { case 1: insertCourse(day, lessonFrom+1, 1, cInfoTmp); break; case 2: insertCourse(day, lessonFrom+1, 1, cInfoTmp); insertCourse(day, lessonFrom+1, 1, cInfoTmp); break; } } } } /** * 将某个课程放入 * @return */ /* private int putCourse(CourseInfo info) { int lessonFrom = info.getLessonfrom(); int lessonTo = info.getLessonto(); // 先按照课程分布将课程按大节切分 ArrayList<int[]> lessonFragments = new ArrayList<int[]>(); for (int i = lessonFrom; i <= lessonTo; i++) { int[] tmpFragment = new int[2]; tmpFragment[0] = i; for (int j = i; j < lessonTo; j++) { for (int k = 0; k < courseDistribution.length; k++) { } } } return 0; } /* private void insertCourse(int day, int lesson, int dummy, CourseInfo info) { Map<String, Object> newMap = new HashMap<String, Object>(); newMap.put("dummy", dummy); newMap.put("course", info); LinkedList<Map<String, Object>> tmpList = weekCourse.get(day-1).get(lesson-1); tmpList.add(newMap); Map<String, Object> tmpMap = tmpList.get(0); tmpMap.put("num", ((Integer)tmpMap.get("num"))+1); tmpMap.put("active", tmpList.size()-1); } */ private boolean isCurrWeek(CourseInfo cInfoTmp) { // 全周 if (cInfoTmp.getWeektype() == 1) { if ((cInfoTmp.getWeekfrom() <= currentWeek) && (currentWeek <= cInfoTmp.getWeekto())) { return true; } else { return false; } } // 单周 else if (cInfoTmp.getWeektype() == 2) { if (currentWeek%2 == 1) { return true; } else { return false; } } // 双周 else { if (currentWeek%2 == 0) { return true; } else { return false; } } } public static Context getContext() { return context; } }