FeedbackTabProvider
import'dart:async';
import'package:flutter/material.dart';
import'package:intl/intl.dart';
import'package:preload_page_view/preload_page_view.dart';
import'package:quickcheck/model/exam_result.dart';
import'package:quickcheck/model/feedbacks.dart'asfeedbacks;
import'package:quickcheck/model/recent_exam.dart'asRecentExam;
import'package:quickcheck/model/feedbacks.dart';
import'package:quickcheck/model/user.dart';
import'package:quickcheck/utils/ApiAdapter.dart';
import'package:quickcheck/utils/shared_prefs.dart';
import'package:quickcheck/view/MypageTab/feedback_list.dart';
import'package:quickcheck/view/feedback_tab/visibility_provider.dart';
import'package:sliding_up_panel/sliding_up_panel.dart';
classFeedbackTabProviderextendsChangeNotifier {
ExamResult _examResult;
FeedbackTabProvider(this._examResult);
GetPoint getPoint;
// int userPoint;
int userId;
// bool showPluse = false;
//미시청에서 시청으로 바뀔때 잠깐보여주는것
finalValueNotifier<bool> showPluse = ValueNotifier<bool>(false);
//전체 시험리스트
RecentExam.RecentExam _recentExam;
//최근시험 리스트
List<RecentExam.Results> resentExamHistory = [];
//TODO: playList, playListReversed, thumbnailLoadingIsDone등은 class따위로
//묶는 것이..
//오늘 어제 전체 피드백영상 리스트
List<List<feedbacks.Results>> _playListAll = [];
//현제플레이되는 영상리스트 처음엔 미시청만
Map<int, List<feedbacks.Results>> playListUnviewd = {};
//key값으로 찾기
varplayListUnviewdKeys = [];
//실제 비디오 플레이시 사용되는 자료
// List<List<feedbacks.Results>> playListReversed = [];
List<List<List<bool>>> thumbnailLoadingIsDone = [];//가장 안쪽 List는 [0]은 thumbnail, [1]은 videoapp controller initialized
int colIndex = 0;
int rowIndex = 0;
int colIndexPlaylist = 0;
int rowIndexPlaylist = 0;
int unviewCount = 0;
int pageInt = 0;
bool loop =true;
bool _visibility =true;
Timer _timer = Timer(Duration(seconds: 0), () =>null);
PanelController panelController = PanelController();
PreloadPageController pageControllerMain =
PreloadPageController(initialPage: 0, keepPage:true,);
int urlId = 0;
//포인트숫자 올라가기전
int userPointRecord = 0;
//포인트 숫자 올라간 후
finalValueNotifier<int> userPoint = ValueNotifier<int>(0);
bool initReady =false;
bool favorate =false;
bool panelOpen =false;
finalValueNotifier<bool> pageMoving = ValueNotifier<bool>(false);
// bool _pageMoving = false;
//index오류
// List<List<feedbacks.Results>> get playList => _playList;
List<List<feedbacks.Results>>getplayList => _playListAll;
//unviewd만
// feedbacks.Results get currentFeedback => _playList[colIndex][rowIndex];
feedbacks.ResultsgetcurrentFeedback => playListUnviewd.values.elementAt(colIndex)[rowIndex];
feedbacks.ResultsgetcurrentFeedbackPlaylist => playListUnviewd.values.elementAt(colIndexPlaylist)[rowIndexPlaylist];
finalValueNotifier<int> counterInt = ValueNotifier<int>(0);
// bool get loop => _loop;
boolgetvisibility => _visibility;
// bool get pageMoving => _pageMoving;
Timergettimer => _timer;
ExamResultgetexamResult => _examResult;
List<String> panelImage = [];
List<String> panelImageForPanel = [];
setVisibility(bool visibility) {
_visibility = visibility;
currentVisibility.setVisibility(visibility);
notifyListeners();
}
setPageMoving(bool pageMovingState) {
pageMoving.value = pageMovingState;
// print('change change change change change change ');
// print('change change change change change change ${pageMoving.value}');
// _pageMoving = pageMoving;
notifyListeners();
}
setTimer(Timer timer) => _timer = timer;
cancelTimer() => _timer.cancel();
Future<void> init(int count)async{
if(count !=null){
unviewCount = count;
}
_recentExam =awaitApiAdapter.getRecentExams(
size: 200, state: 'E', noAssignment:false);
// DateFormat.yMMMd().format(DateTime.now()) != DateFormat.yMMMd().format(DateTime.parse(_recentExam.results.first.createdAt).toLocal())
//최근 시험 데이터 받아오기
// if (DateTime.now().difference(DateTime.parse(_recentExam.results.first.createdAt).toLocal()).inDays == 0) {
if(DateFormat.yMMMd().format(DateTime.now()) == DateFormat.yMMMd().format(DateTime.parse(_recentExam.results.first.createdAt).toLocal())) {
//마지막 시험본게 오늘일 경우,오늘 시험만을 가져옴.
_recentExam.results.forEach((e) {
// if (DateTime.now().difference(DateTime.parse(e.createdAt).toLocal()).inDays == 0) {
if(DateFormat.yMMMd().format(DateTime.now()) == DateFormat.yMMMd().format(DateTime.parse(e.createdAt).toLocal())) {
// print('이거???이거??? ${e.exam.chapter}챕터 : ${e.exam.questionType.id}회차');
resentExamHistory.add(e);
}
});
print(
'resentExamHistory resentExamHistory resentExamHistory ${resentExamHistory.length}');
// resentExamHistory.add(value);
}else if(DateFormat.yMMMd().format(DateTime.now()) != DateFormat.yMMMd().format(DateTime.parse(_recentExam.results.first.createdAt).toLocal())) {
//마지막 시험본게 어제일 경우,어제의 피드백을 가져 옴.
_recentExam.results.forEach((e) {
if(DateFormat.yMMMd().format(DateTime.parse(_recentExam.results.first.createdAt).toLocal()) == DateFormat.yMMMd().format(DateTime.parse(e.createdAt).toLocal())) {
// print('이전1이전1이전1이전1이전1이전1이전1이전1이전1이전1이전1이전1이전1이전1 ');
// print('이거???이거??? ${e.exam.chapter}챕터 : ${e.exam.questionType.id}회차');
resentExamHistory.add(e);
}
});
}
//시험 데이터를 기반으로 데이터 받아오기 (_feedbackList채우기)
// _feedbackList = [qid1, qid2, qid3]
List<List<feedbacks.Results>> _feedbackList = [];
if(resentExamHistory.length != 0) {
// for문 방식
//전체 시험들을 iterate
print('resentExamHistory.length resentExamHistory.length ${resentExamHistory.length}');
for(vari = 0; i < resentExamHistory.length; i++) {
//각각의 question type들을 전부 iterate
//TODO:가장 최근에 본 시험이 chapter 10의 1회차, chapter 2의 3회차 라면,
//아래 for loop은 1회차 시험만 보는 것이 아닌가요?
// for (var j = 0; j < resentExamHistory[0].exam.questionType.id; j++) {
int latestQuestiontypeId = 3;
for(varj = 0; j < latestQuestiontypeId; j++) {
//전체 시험들을 통해,각각의 exam.id와 questionTypeId를 구하고,
//이를 이용하여 getFeedbackList()
print('resentExamHistory[i].exam.id resentExamHistory[i].exam.id ${resentExamHistory[i].exam.id}');
Feedbacks result =awaitApiAdapter.getFeedbackList(
resentExamHistory[i].exam.id,
questionType: j + 1);
//여기 물어볼것 questionType 1로받고 questionType 2로받았을때 questionType 1과 questionType 2가 다를수도있으니 로직이 잘못됬을수도...
if(result.results.isNotEmpty) {
_feedbackList.add(result.results.map((e) => e).toList());
// sort by voca id
_feedbackList[j].sort((a, b) =>
a.feedback.vocabulary.id.compareTo(b.feedback.vocabulary.id));
print('_feedbackList _feedbackList ${_feedbackList[0].length}');
}
}
}
}
// _playList를 완성.
// _playList = [voca1, voca2, ..., vocaN]
//전체 vocabulary개수를 알 수 없기 때문에, Map(rawPlayList)을 일단 만들고,
//이후에 _playList를 채움.
Map<int, List<feedbacks.Results>> rawPlayList =
{};//이것을 기반으로 _playList만듬.
_feedbackList.forEach((elemList) {
elemList.forEach((elem) {
int key = elem.feedback.vocabulary.id;
if(rawPlayList.containsKey(key)) {
rawPlayList[key].add(elem);
}else{
rawPlayList[key] = [elem];
}
});
});
// rawPlayList -> _playList
List<int> sortedKeys = rawPlayList.keys.toList();
// sorting first
sortedKeys.forEach((element) {
rawPlayList[element].sort(
(a, b) => a.feedback.level.compareTo(b.feedback.level));// sort first
//플레이리스트 추가
_playListAll.add(rawPlayList[element].toList());// add to playlist
});
//암본것 위로 올리기
// sortedKeys.forEach((element) {
// //플레이리스트 추가
// _playList.add(rawPlayList[element].toList()); // add to playlist
// });
// // then add unviewed
// sortedKeys.forEach((element) {
// // last가 가장 최근 피드백 영상일 것임.
// //최근 피드백 영상이 항상 포커스이므로 이 모델을 기준으로 추가.
// if (rawPlayList[element].last.viewed == false) {
// _playList.add(rawPlayList[element].toList()); // add to playlist
// }
// });
//
// // add viewed
// sortedKeys.forEach((element) {
// //그 외 이미 본 단어들을 추가
// if (rawPlayList[element].last.viewed) {
// _playList.add(rawPlayList[element].toList()); // add to playlist
// }
// });
// _playList -> playListReversed and panelImage
//_playList의 자료는 형식이 {{3,2,1},{3,2,1},{3,2,1}}로 되어있어서 .reversed를 통해서 순서를 바꾸어줍니다
//실제 사용하는건 = playListReversed입니다
for(vari = 0; i < _playListAll.length; i++) {
// playListReversed.add(_playList[i].reversed.toList());
//순서때문에 .first가
panelImageForPanel.add(_playListAll[i].last.feedback.thumbnail);
// thumbnailLoadingIsDone.add(_playList[i].map((_) => [false, false]).toList());
if(!_playListAll[i].last.viewed){
playListUnviewd.addAll({i : _playListAll[i].toList()});
}
}
playListUnviewdKeys.add(playListUnviewd);
for(vari = 0; i < playListUnviewd.keys.length; i++){
panelImage.add(playListUnviewd.values.elementAt(i).last.feedback.thumbnail);
thumbnailLoadingIsDone.add(playListUnviewd.values.elementAt(i).map((_) => [false,false]).toList());
}
print('playListUnviewd playListUnviewd ${playListUnviewd.keys}');
userId = SharedPrefs().userId;
//현제 포인트
ApiAdapter.getUserPoint(userId).then((value) {
getPoint = value;
userPoint.value = value.pointResults.first.amount;
userPointRecord = value.pointResults.first.amount;
});
colIndex = 0;
rowIndex = _playListAll[0].length - 1;
// rowIndex = playListReversed[0].length - 1;
favorate = currentFeedback.saved;
initReady =true;
notifyListeners();
}
//시청완료인것을 눌렀을때 화면에 추가하고 다시띄줘주기
voidsetplayListUnviewd2(int index){
print('playListUnviewd playListUnviewd ${playListUnviewd.keys}');
//추가
playListUnviewd.addAll({index : _playListAll[index].toList()});
varmapEntries = playListUnviewd.entries.toList()
..sort((a, b) => a.key.compareTo(b.key));
playListUnviewd
..clear()
..addEntries(mapEntries);
print('playListUnviewd2 playListUnviewd2 ${playListUnviewd.keys}');
//비워주기
panelImage.clear();
thumbnailLoadingIsDone.clear();
playListUnviewdKeys.clear();
for(vari = 0; i < playListUnviewd.keys.length; i++){
panelImage.add(playListUnviewd.values.elementAt(i).last.feedback.thumbnail);
thumbnailLoadingIsDone.add(playListUnviewd.values.elementAt(i).map((_) => [false,false]).toList());
}
playListUnviewdKeys.add(playListUnviewd);
notifyListeners();
}
Future<Feedbacks> getFeedbackList(int questionType) {
returnApiAdapter.getFeedbackList(_examResult.id,
questionType: questionType);
}
voidsetPoint() {
userId = SharedPrefs().userId;
// int _selectedBookId = SharedPrefs().bookId;
//현제 포인트
ApiAdapter.getUserPoint(userId).then((value) {
userPoint.value = value.pointResults.first.amount;
});
notifyListeners();
}
voidsetPointRecord(int point) {
userPointRecord = point;
notifyListeners();
}
// void setSaved(int id, bool saved, int vertical, int horizontal){
voidsetSaved(int id, bool saved) {
ApiAdapter.patchFeedback(id, saved: !saved);
currentFeedback.saved = !saved;
_playListAll[colIndex][rowIndex].saved = !saved;
// playListReversed[vertical][horizontal].saved = !saved;
notifyListeners();
}
//좋아요 저장
voidsetliked(int id, bool liked, int vertical, int horizontal) {
print('id id id id $id');
ApiAdapter.patchFeedback(id, liked: liked);
// playListReversed[vertical][horizontal].liked = !liked;
_playListAll[vertical][horizontal].liked = !liked;
notifyListeners();
}
//현제 플레이되고있는 리스트의 가로 세로
setColindexRowIndex({int colIndexP , int rowIndexP}){
if(colIndexP !=null){
colIndexPlaylist = colIndexP;
}
if(rowIndexP !=null){
rowIndexPlaylist = rowIndexP;
}
notifyListeners();
}
voidsetPageInt(int page) {
pageControllerMain =newPreloadPageController(initialPage: page);
notifyListeners();
}
//본거 안본거
voidsetView(int ver, int hori, int unviewedIndex) {
// playListReversed[ver][hori].viewed = true;
_playListAll[ver][hori].viewed =true;
playListUnviewd.values.elementAt(unviewedIndex)[hori].viewed =true;
// for (var i = 0; i > _playList[ver].length; i++) {
// // if (playListReversed[ver][hori].id == _playList[ver][i].id) {
// if (_playList[ver][hori].id == _playList[ver][i].id) {
// _playList[ver][i].viewed = true;
// }
// }
notifyListeners();
}
voidsetPage(int page) {
pageControllerMain.jumpToPage(page);
setVisibility(false);
currentVisibility.setVisibility(false);
notifyListeners();
}
//영상 저장
voidsetFavorate(bool _favorate) {
favorate = _favorate;
notifyListeners();
}
//반복
voidsetLoop(bool loopState) {
loop = loopState;
notifyListeners();
}
//panel열리고 닫히는것 확인
voidsetPanelOpen(bool open) {
if(open){
panelController.open();
}else if(!open){
panelController.close();
}
panelOpen = open;
notifyListeners();
}
voidsetShowPluse(bool plus){
showPluse.value = plus;
notifyListeners();
}
voidsetJumpPage(int page) {
// int different = 0;
// int different = page - colIndex;
// var index = playListUnviewd2.indexWhere((map) => map[page] == 0);
varindex;
for(vari = 0; i < playListUnviewd.keys.length; i++){
if(playListUnviewd.keys.elementAt(i) == page){
index = i;
}
}
// pageControllerMain = new PreloadPageController(initialPage: index);
// pageControllerMain.animateToPage(index, duration: Duration(milliseconds: 100), curve: Curves.fastOutSlowIn);
pageControllerMain.jumpToPage(index);
print('index index index index index index index index ${index + 1}');
// // different.abs();
// print('차이 차이 차이 ${different.abs()}');
// print('12312312321312312313 123123123123123 ${page - colIndex}');
// print('12312312321312312313 123123123123123 ${different.abs()}');
// if (different.abs() != 0) {
// pageControllerMain.jumpToPage(page);
// print('hdbfaijhdjkbnaskfnak;jsndf ${pageControllerMain.page}');
// pageControllerMain.animateToPage(page,
// duration: Duration(milliseconds: 10),
// // curve: Curves.ease,
// curve: Curves.fastOutSlowIn);
// pageControllerMain.jumpTo(page.toDouble());
// Future.delayed(Duration(milliseconds: 500), () async {
// pageControllerMain.animateToPage(page,
// duration: different.abs() <= 2
// ? Duration(milliseconds: 500)
// : different.abs() > 2 && different.abs() < 7
// ? Duration(milliseconds: 1500)
// : Duration(milliseconds: 2200),
// // curve: Curves.ease,
// curve: Curves.fastOutSlowIn);
// });
// }
setVisibility(false);
currentVisibility.setVisibility(false);
notifyListeners();
}
}
FeedbackTabPlay
import'package:flutter/foundation.dart';
import'package:flutter/material.dart';
import'package:flutter/painting.dart'asfp;
import'package:googleapis/gamesconfiguration/v1configuration.dart';
import'package:line_awesome_flutter/line_awesome_flutter.dart';
import'package:lottie/lottie.dart';
import'package:provider/provider.dart';
import'package:quickcheck/model/exam_result.dart';
import'package:quickcheck/utils/ApiAdapter.dart';
import'package:quickcheck/utils/show_message.dart';
import'package:quickcheck/view/Common/tab_page.dart';
import'package:quickcheck/view/Common/tab_page_provider.dart';
import'package:quickcheck/view/TestTab/feedback_play.dart';
import'package:quickcheck/model/recent_exam.dart'asRecentExam;
import'package:quickcheck/view/feedback_tab/feedback_recommend_video.dart';
import'package:quickcheck/view/feedback_tab/visibility_provider.dart';
import'package:sizer/sizer.dart';
import'../../theme_provider.dart';
import'dart:async';
import'dart:ui';
import'package:camera/camera.dart';
import'package:flutter/cupertino.dart';
import'package:flutter/material.dart';
import'package:flutter/services.dart';
import'package:intl/intl.dart';
import'package:mccounting_text/mccounting_text.dart';
import'package:preload_page_view/preload_page_view.dart';
import'package:provider/provider.dart';
import'package:quickcheck/model/exam_result.dart';
import'package:quickcheck/model/feedbacks.dart'asfeedbacks;
import'package:quickcheck/style.dart';
import'package:quickcheck/view/TestTab/preload_player.dart';
import'package:quickcheck/view/TestTab/preload_player_chewie.dart';
import'package:quickcheck/view/feedback_tab/feedback_tab_preload.dart';
import'package:quickcheck/view/feedback_tab/feedback_tab_provider.dart';
import'package:quickcheck/view/feedback_tab/visibility_provider.dart';
import'package:sliding_up_panel/sliding_up_panel.dart';
import'package:flutter_screenutil/flutter_screenutil.dart';
import'package:video_player/video_player.dart';
import'package:sizer/sizer.dart';
classFeedbackTabPlayextendsStatefulWidget {
@override
_FeedbackTabPlayState createState() => _FeedbackTabPlayState();
}
class_FeedbackTabPlayStateextendsState<FeedbackTabPlay> {
RecentExam.RecentExam recentExam;
ExamResult examResult = ExamResult();
bool _isLoading =true;
@override
voiddidChangeDependencies() {
super.didChangeDependencies();
getReady();
}
getReady()async{
recentExam =awaitApiAdapter.getRecentExams(
size: 200, state: 'E', noAssignment:false);
print(' _recentExam ${recentExam.results.length}');
print(' _recentExam okok');
if(recentExam.results.length != 0) {
examResult =awaitApiAdapter.getExamResult(recentExam.results.first.id);
print(' examResult okok');
}
if(mounted) {
setState(() {
_isLoading =false;
});
}
}
@override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(statusBarColor: Colors.transparent),
);
return_isLoading
? Scaffold(
body: Container(
child: Center(
child: CircularProgressIndicator(),
),
),
)
: recentExam.results.length == 0
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'재생할 피드백 영상이 없습니다',
style: TextStyle(
fontSize: 18.sp, fontWeight: FontWeight.bold),
),
Text(
'기억도 체크를 진행하고',
style: TextStyle(
fontSize: 18.sp, fontWeight: FontWeight.bold),
),
Text(
'나만의 피드백 영상을 받아보세요',
style: TextStyle(
fontSize: 18.sp, fontWeight: FontWeight.bold),
),
Container(
height: 10,
),
InkWell(
onTap: () {},
child: Container(
padding: EdgeInsets.only(
top: 5, bottom: 5, left: 10, right: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: mainThemeColor(),
),
child: Padding(
padding:constEdgeInsets.symmetric(
horizontal: 15.0, vertical: 8.0),
child: Text("기억도 체크하기",
style: TextStyle(
fontSize: 15.sp,
color: Colors.black,
fontWeight: FontWeight.bold)),
),
),
),
],
),
)
//프로바이더 적용
: ChangeNotifierProvider.value(
value: FeedbackTabProvider(examResult),
child: Material(
child: FeedbackTabPlayV(0),
),
);
}
}
classFeedbackTabPlayVextendsStatefulWidget {
finalint pageInt;
FeedbackTabPlayV(this.pageInt);
@override
_FeedbackTabPlayVState createState() => _FeedbackTabPlayVState();
}
//페넬 현제페이지의 퍼센트계산한다은 실시간으로 바텀네비 줄여주기
finalValueNotifier<double> playerExpandProgress =
ValueNotifier(playerMinHeight);
//
// // ValueNotifier<bool> currentlyPlaying = ValueNotifier(null);
//
constdouble playerMinHeight = 80;
constdouble playerMaxHeight = 370;
constminiplayerPercentageDeclaration = 0.1;
class_FeedbackTabPlayVStateextendsState<FeedbackTabPlayV> {
final_scaffoldKey = GlobalKey<ScaffoldState>();
//child를 리프래시 시키는 int
int _count = 0;
bool visibility =true;
int currentIndex = 2;
//사진 이미지 다받아왔는지 확인
bool _isLoading =true;
double _fabHeight;
double _panelHeightOpen;
bool isReady =false;
//블러용
double _sigmaX = 10.0;// from 0-10
double _sigmaY = 10.0;// from 0-10
double _opacity = 0.5;// from 0-1.0
//
// //TODO:페넬 닫았을때 높이
double _panelHeightClosed = 11.0.h;
finaldouble _initFabHeight = 0;
//페넬안에 이미지
List<String> providerPanelImages = List<String>();
List<NetworkImage> thumbnails = List<NetworkImage>();
@override
voidinitState() {
super.initState();
Future.delayed(Duration.zero, ()async{
context.read<FeedbackTabProvider>().init(Provider.of<TabPageProvider>(context, listen:false).counterForFeedback.value);
varfeedbackModel = Provider.of<FeedbackTabProvider>(context, listen:false);
//세로 initial page세팅
feedbackModel.setPageInt(widget.pageInt);
});
_fabHeight = _initFabHeight;
currentVisibility.addListener(() {
visibility = currentVisibility.visibility.value;
});
}
@override
voiddispose() {
super.dispose();
// _tabController.dispose();
}
void_buildThumbnailImages() {
// Thumbnail이미지 미리 생성
varfeedbackModel = Provider.of<FeedbackTabProvider>(context, listen:false);
if(feedbackModel.panelImageForPanel.length == providerPanelImages.length)return;
providerPanelImages = List.from(feedbackModel.panelImageForPanel);
List<bool> isThumbnailLoaded = List.filled(providerPanelImages.length,false);
providerPanelImages.asMap().forEach((idx, element) {
varni = NetworkImage(element);
ni.resolve(fp.ImageConfiguration())
.addListener(ImageStreamListener(
(info, call) {
isThumbnailLoaded[idx] =true;
//전체 다 확인 후 로딩 완료되었다면, _isLoading = true;
if(isThumbnailLoaded.contains(false))return;
setState(() {
_isLoading =false;
});
}));
thumbnails.add(ni);
});
}
@override
Widget build(BuildContext context) {
_panelHeightOpen = MediaQuery.of(context).size.height * .80;
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(statusBarColor: Colors.transparent),
);
_buildThumbnailImages();
finalfeedbackModel = Provider.of<FeedbackTabProvider>(context);
returnMaterial(
// child:
child: _isLoading || (// Loading은 thumbnail이미지 로딩까지 완료된 후에 true
!feedbackModel.initReady &&
feedbackModel.playList.isNotEmpty)
? Container(
child: Center(
child: CircularProgressIndicator(),
))
//페넹 붙이기
: SlidingUpPanel(
controller: Provider.of<FeedbackTabProvider>(context).panelController,
maxHeight: 97.0.h,
minHeight: feedbackModel.visibility ? _panelHeightClosed : 0,
//배경색
// color: playerExpandProgress.value < 81.0 ? Colors.transparent : Colors.white,
// color: Colors.black.withOpacity(_opacity),
color: Colors.transparent,
backdropEnabled:true,
backdropColor: Colors.transparent,
backdropTapClosesPanel:true,
parallaxEnabled:false,
// parallaxOffset: .5,
boxShadow: <BoxShadow>[
BoxShadow(
blurRadius: 0,
color: Colors.transparent,
)
],
body: feedbackModel.playList.isEmpty
? Container(
color: Colors.black,
)
: _body(),
panelBuilder: (sc) => _panel(sc),
borderRadius: playerExpandProgress.value > 30.0
? BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20))
: BorderRadius.only(),
onPanelSlide: (double pos) => setState(
() {
playerExpandProgress.value =
pos * (97.0.h - _panelHeightClosed) + _initFabHeight;
},
),
),
);
}
Widget _panel(ScrollController sc) {
finalfeedbackModel = Provider.of<FeedbackTabProvider>(context);
returnfeedbackModel.initReady ==false
? Container(
child: Center(
child: CircularProgressIndicator(),
),
)
: AnimatedSwitcher(
duration: Duration(milliseconds: 10),
reverseDuration: Duration(milliseconds: 10),
transitionBuilder: (Widget child, Animation<double> animation) {
returnFadeTransition(opacity: animation, child: child);
},
child: Container(
key: ValueKey(playerExpandProgress.value),
child: playerExpandProgress.value > 80.0
? BackdropFilter(
filter:
ImageFilter.blur(sigmaX: _sigmaX, sigmaY: _sigmaY),
child: Container(
color: Colors.black.withOpacity(_opacity),
child: ListView(
physics: ClampingScrollPhysics(),
controller: sc,
children: <Widget>[
SizedBox(
height: 12.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 30,
height: 5,
decoration: playerExpandProgress.value > 81.0
? BoxDecoration(
color: Colors.black.withOpacity(0.1),
// color: Colors.grey[300],
borderRadius: BorderRadius.all(
Radius.circular(12.0)))
: BoxDecoration(),
),
],
),
InkWell(
onTap: () {
feedbackModel.panelController
.animatePanelToPosition(0,
duration: Duration(milliseconds: 300),
curve: Curves.easeInCirc);
feedbackModel.setPanelOpen(false);
},
child: SizedBox(
height: 15.0,
),
),
InkWell(
onTap: () {
feedbackModel.panelController
.animatePanelToPosition(0,
duration: Duration(milliseconds: 300),
curve: Curves.easeInCirc);
feedbackModel.setPanelOpen(false);
},
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 20.0, vertical: 10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
// Text(
// "챕터 ${widget._examResult.exam.chapter}피드백 목록",
// style: baseTextBStyle().copyWith(fontSize: 20.sp),
// ),
Text(
"총 ${feedbackModel.playList.length}단어",
// '$playerExpandProgress , $_panelHeightClosed',
style: regularTextStyle()
.copyWith(color: Colors.white),
),
],
),
),
),
Column(
children: [
//묶는거 보류
ListView.builder(
shrinkWrap:true,
physics: NeverScrollableScrollPhysics(),
itemCount: feedbackModel.playList.length,
itemBuilder: (BuildContext context, int index) {
returnColumn(
children: [
//만약 첫번째 index이고 미시청이거나 미시청이고 전꺼랑 챕터가 같지 않으면
if(index == 0 && !feedbackModel.playList[index].last.viewed
|| !feedbackModel.playList[index].last.viewed
&& feedbackModel.playList[index].last.relatedExam.chapter != feedbackModel.playList[index - 1].last.relatedExam.chapter
)
Column(
children: [
Text('미시청 영상',
style: TextStyle(fontSize: 17.sp, fontWeight: FontWeight.bold, color: Colors.grey[500]),
),
Text('${feedbackModel.playList[index].last.relatedExam.chapter}챕터',
style: TextStyle(fontSize: 17.sp, fontWeight: FontWeight.bold, color: Colors.grey[500]),
),
],
),
//만약 첫번째 index이고 시청이거나 시청이고 전꺼랑 같지않으면
if(index == 0 && feedbackModel.playList[index].last.viewed
|| feedbackModel.playList[index].last.viewed
&& feedbackModel.playList[index].last.relatedExam.chapter != feedbackModel.playList[index - 1].last.relatedExam.chapter)
Text('${feedbackModel.playList[index].last.relatedExam.chapter}챕터',
style: TextStyle(fontSize: 17.sp, fontWeight: FontWeight.bold, color: Colors.grey[500]),
),
InkWell(
onTap: () {
// feedbackModel.panelController.close();
currentVisibility.setVisibility(false);
feedbackModel.setplayListUnviewd2(index);
// if(!feedbackModel.playList[index].last.viewed){
//
// } else {
// feedbackModel.setJumpPage(index);
// _key.currentState.dispose();
// _key.currentState.;
if(mounted)// await과 setState()의 사이..
setState(() => ++_count);
feedbackModel.setJumpPage(index);
feedbackModel.setPanelOpen(false);
// feedbackModel.setJumpPage(index);
},
child: _buildWordItem(
feedbackModel.playList[index],
index,
),
),
],
);
}
),
],
),
SizedBox(
height: 24,
),
],
),
),
)
: feedbackModel.visibility
? BackdropFilter(
filter: ImageFilter.blur(
sigmaX: _sigmaX, sigmaY: _sigmaY),
child: Container(
color: Colors.black.withOpacity(_opacity),
// width: 100.0.w,
child: Container(
// height: 9.0.h,
// color: Colors.red,
child: Column(
children: [
Padding(
padding:constEdgeInsets.only(top: 8.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
// crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(
onPressed: () {
feedbackModel.setSaved(
feedbackModel
.currentFeedback.id,
feedbackModel
.currentFeedback.saved);
if(feedbackModel.favorate) {
feedbackModel
.setFavorate(false);
_scaffoldKey.currentState
.showSnackBar(CustomMessage
.displaySnackBar(
'즐겨찾기에서 해제되었습니다'));
}else{
feedbackModel.setFavorate(true);
_scaffoldKey.currentState
.showSnackBar(CustomMessage
.displaySnackBar(
'즐겨찾기에 등록이 되었습니다'));
}
},
padding: EdgeInsets.symmetric(
horizontal: 5.0.w, vertical: 5),
icon: Icon(
feedbackModel.favorate
? Icons.star_rounded
: Icons.star_border_rounded,
size: 5.0.h,
color: Colors.white,
),
),
Container(
width: 3.0.w,
),
InkWell(
onTap: () {
feedbackModel.panelController
.animatePanelToPosition(1,
duration: Duration(
milliseconds: 400),
curve:
Curves.easeOutCirc);
feedbackModel.setPanelOpen(true);
},
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
feedbackModel.playList.isEmpty
? ""
// : "${feedbackModel.playListReversed[widget.verticalPageIndex][widget.horizontalpageIndex].feedback.vocabulary.word}",
: "${feedbackModel.currentFeedbackPlaylist.feedback.vocabulary.word}",
style: headerTextStyle()
.copyWith(
color: Colors.white),
),
Text(
feedbackModel.playList.isEmpty
? ""
// : "${widget.horizontalpageIndex + 1}단계 피드백",
: "${feedbackModel.rowIndex + 1}단계 피드백",
style: baseTextStyle()
.copyWith(
color: Colors.white,
fontSize: 11.0.sp),
),
],
),
),
Expanded(
child: InkWell(
onTap: () {
feedbackModel.panelController
.animatePanelToPosition(1,
duration: Duration(
milliseconds:
400),
curve: Curves
.easeOutCirc);
feedbackModel
.setPanelOpen(true);
},
child: Container()),
),
Padding(
padding:constEdgeInsets.symmetric(
horizontal: 10.0),
child: Container(
height: 8.0.h,
width: 15.0.w,
decoration: BoxDecoration(
color: Colors.black
.withOpacity(0.1),
borderRadius: BorderRadius.all(
Radius.circular(12.0)),
),
child: IconButton(
onPressed: () {
if(feedbackModel.loop) {
feedbackModel
.setLoop(false);
}else{
feedbackModel.setLoop(true);
}
// feedbackModel._loop = feedbackModel.loop;
print(
'loop loop loop loop loop ${feedbackModel.loop}');
// setState(() {
// loop = !loop;
// _controller.setLooping(loop);
// });
},
icon: Icon(
feedbackModel.loop
? Icons.repeat_one
: Icons.repeat,
// Icons.repeat,
size: 25.0.sp,
color: Colors.white,
),
),
),
),
Container(
height: 8.0.h,
width: 15.0.w,
decoration: BoxDecoration(
color:
Colors.black.withOpacity(0.1),
borderRadius: BorderRadius.all(
Radius.circular(12.0)),
),
child: IconButton(
onPressed: () {
feedbackModel.panelController
.animatePanelToPosition(1,
duration: Duration(
milliseconds: 400),
curve:
Curves.easeOutCirc);
feedbackModel
.setPanelOpen(true);
},
icon: Icon(
Icons.playlist_play,
size: 25.0.sp,
color: Colors.white,
),
),
),
Container(
width: 2.0.w,
),
],
),
),
],
),
),
),
)
: Container(),
),
);
}
//페넬안에 플레이리스트 카드 한개한개
Container _buildWordItem(List<feedbacks.Results> voca, int index) {
finalfeedbackModel = Provider.of<FeedbackTabProvider>(context);
returnContainer(
child: Column(
children: [
Container(
color: Colors.white.withOpacity(0.2),
padding: EdgeInsets.only(left: 20, right: 20, top: 10, bottom: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(10),
),
child: Container(
width: 55.w,
height: 55.h,
decoration: BoxDecoration(
image: DecorationImage(
image: thumbnails[index],//미리 로딩된 것을 사용.
fit: BoxFit.cover,
),
),
child: Stack(
children: [
Visibility(
visible:
feedbackModel.playList[index].last.viewed,
child: Positioned(
bottom: 0,
child: Container(
alignment: Alignment.center,
width: 55.w / 3 * 2,
height: 55.h * 0.23,
color: Colors.black.withOpacity(0.6),
child: Text(
"학습완료",
style: baseTextStyle().copyWith(
color: Colors.white, fontSize: 8.sp),
),
),
),
),
Visibility(
visible: feedbackModel.currentFeedbackPlaylist.feedback.vocabulary.word == voca.last.feedback.vocabulary.word ?true:false,
child: Center(
child: Lottie.asset(
"assets/play_button.json",
width: 80,
repeat:true,
fit: BoxFit.cover),
// Icon(
// Icons.play_circle_fill,
// color: Colors.red,
// size: 10.0.w,
// ),
),
),
// ValueListenableBuilder<int>(
// valueListenable: feedbackModel.counterInt,
// builder: (context, int value, child) {
// return Visibility(
// visible: value == index ? true : false,
// child: Center(
// child: Lottie.asset(
// "assets/play_button.json",
// width: 80,
// repeat: true,
// fit: BoxFit.cover),
// // Icon(
// // Icons.play_circle_fill,
// // color: Colors.red,
// // size: 10.0.w,
// // ),
// ),
// );
// }),
],
)),
),
],
),
Padding(padding: EdgeInsets.only(left: 10)),
// Expanded(
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
voca.last.feedback.vocabulary.word,
style:
TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
maxLines: 1,
overflow: TextOverflow.fade,
),
Text(
"${voca.last.feedback.level}번째 피드백",
style: TextStyle(
fontSize: 15, color: Colors.white.withOpacity(0.5)),
),
],
),
],
),
),
Container(
height: 0.2,
color: Colors.white.withOpacity(0.5),
),
],
),
);
}
//세로 가로 비디오플레이로 넘어감
Widget _body() {
returnFeedbackTabPreload(
//key값으로 리프레쉬
key: ValueKey<int>(_count),
);
}
}
FeedbackTabPreload
import'dart:async';
import'dart:math';
import'package:like_button/like_button.dart';
import'package:line_awesome_flutter/line_awesome_flutter.dart';
import'package:lottie/lottie.dart';
import'package:mccounting_text/mccounting_text.dart';
import'package:provider/provider.dart';
import'package:quickcheck/model/user.dart';
import'package:quickcheck/utils/ApiAdapter.dart';
import'package:quickcheck/utils/shared_prefs.dart';
import'package:quickcheck/utils/show_message.dart';
import'package:quickcheck/view/Common/tab_page.dart';
import'package:quickcheck/view/Common/tab_page_provider.dart';
import'package:quickcheck/view/TestTab/feedback_result.dart';
import'package:quickcheck/view/feedback_tab/feedback_tab_play.dart';
import'package:quickcheck/view/feedback_tab/feedback_tab_provider.dart';
import'package:smooth_page_indicator/smooth_page_indicator.dart';
import'package:video_player/video_player.dart';
import'package:flutter/material.dart';
import'package:preload_page_view/preload_page_view.dart';
import'package:quickcheck/style.dart';
import'package:flutter_screenutil/flutter_screenutil.dart';
import'package:flutter/services.dart';
import'package:quickcheck/model/feedbacks.dart'asfeedbacks;
import'package:sizer/sizer.dart';
// import 'package:scrolling_page_indicator/scrolling_page_indicator.dart';
classFeedbackTabPreloadextendsStatefulWidget {
constFeedbackTabPreload({Key key}) :super(key: key);
@override
FeedbackTabPreloadState createState() => FeedbackTabPreloadState();
}
classFeedbackTabPreloadStateextendsState<FeedbackTabPreload>withTickerProviderStateMixin {
//스넥바용
final_scaffoldKey = GlobalKey<ScaffoldState>();
//세로 페이지가 완전히 바뀌고나서 저장되는 값
int currentVertical = 0;
double currentVerticalPageDouble = 0;
double currentHorizontalPageDouble = 0;
//현제 세로페이지가 움직이는 상테인지
bool verticalIsOnPageTurning =false;
bool verticalVisibility =true;
// ScrollPhysics verticalPreloadPhysics = new NeverScrollableScrollPhysics();
voidinitController() {
// FeedbackProvider feedbackModel =
// Provider.of<FeedbackProvider>(context, listen: false);
FeedbackTabProvider feedbackModel = Provider.of<FeedbackTabProvider>(context, listen:false);
varscrollListener;
scrollListener = () {
// print("scrollListener - ${feedbackModel.pageControllerMain.page},${feedbackModel.pageControllerMain.position}");
/////////////////////////////////////////////
// horizontal blocking when loading is not done
/////////////////////////////////////////////
Future.delayed(Duration.zero, ()async{
setState(() {
currentVerticalPageDouble = feedbackModel.pageControllerMain.page;
});
});
// setState(() {
// currentDouble = feedbackModel.pageControllerMain.page;
// });
// called after image loading.
varcvIdx = feedbackModel.pageControllerMain.page.round();
varchIdx = currentHorizontalPageDouble.round();
// var vMax = feedbackModel.playListReversed.length;
varvMax = feedbackModel.playListUnviewd.keys.length;
// var hMax = feedbackModel.playListReversed[cvIdx].length;
//현재 보고 있는 페이지를 기준으로 업데이트.
//어디로 로딩할지 모르기 때문에,상하좌우 전부 검사하여 하나라도 false이면 못움직이게 막음.
// min(), max()는 boundry check용
varup = feedbackModel.thumbnailLoadingIsDone[max(0, cvIdx - 1)][chIdx];
vardown = feedbackModel.thumbnailLoadingIsDone[min(vMax - 1, cvIdx + 1)][chIdx];
// print("ImageStreamListener - ${cvIdx},${vMax},${chIdx},${hMax}, ${up},${down},${right},${left}");
if((!(up[0] && up[1]) && feedbackModel.pageControllerMain.page < feedbackModel.pageControllerMain.page.round()) ||
(!(down[0] && down[1]) && feedbackModel.pageControllerMain.page > feedbackModel.pageControllerMain.page.round())) {
//위가 아직 로딩되지 않았는데 올라가려고 하는 경우,혹은 아래가 아직 로딩되지 않았는데 내려가려고 하느 경우.
//TODO:안넘어가는 조건부분 :로딩바 넣어주세요.
feedbackModel.pageControllerMain.jumpToPage(cvIdx.toInt());
}
if(verticalIsOnPageTurning &&
feedbackModel.pageControllerMain.page == feedbackModel.pageControllerMain.page.roundToDouble()) {
print('11111111111111');
feedbackModel.setPageMoving(false);
// print('움직인다 움직인다 움직인다 1111111');
setState(() {
currentVertical = feedbackModel.pageControllerMain.page.toInt();
verticalIsOnPageTurning =false;
});
}else if(!verticalIsOnPageTurning && currentVertical.toDouble() != feedbackModel.pageControllerMain.page) {
feedbackModel.setPageMoving(true);
// print('움직인다 움직인다 움직인다 3333333');
//포인트 올라간거 확인하고 포인트 맞춰주는 곳
if(feedbackModel.userPointRecord != feedbackModel.userPoint.value){
feedbackModel.setPointRecord(feedbackModel.userPoint.value);
}
//움직일때 프로그래시브바 숨겨두기
if((currentVertical.toDouble() - feedbackModel.pageControllerMain.page).abs() < 0.002) {
print('3333333');
feedbackModel.setPageMoving(false);
}
// print('움직인다 움직인다 움직인다 22222');
// print('움직인다 움직인다 움직인다 ${(current.toDouble() - feedbackModel.pageControllerMain.page).abs()}');
if((currentVertical.toDouble() - feedbackModel.pageControllerMain.page).abs() > 0.8) {
// print('움직인다 움직인다 움직인다 3333333');
setState(() {
verticalIsOnPageTurning =true;
});
// _scaffoldKey.currentState.removeCurrentSnackBar();
}
}
};
feedbackModel.pageControllerMain.addListener(scrollListener);
}
@override
voidinitState() {
super.initState();
initController();
}
@override
voiddispose() {
// initController();
super.dispose();
}
@override
Widget build(BuildContext context) {
// FeedbackProvider feedbackModel =
// Provider.of<FeedbackProvider>(context, listen: false);
FeedbackTabProvider feedbackModel = Provider.of<FeedbackTabProvider>(context);
returnScaffold(
key: _scaffoldKey,
body: Builder(builder: (BuildContext context) {
returnStack(
alignment: Alignment.center,
children: [
Container(
height: MediaQuery.of(context).size.height,
color: Colors.black,
child: PreloadPageView.builder(
controller: feedbackModel.pageControllerMain,
scrollDirection: Axis.vertical,
itemCount: feedbackModel.playListUnviewd.keys.length,
// preloadPagesCount: feedbackModel.playListReversed.length,
preloadPagesCount: 3,
// physics: verticalPreloadPhysics,
itemBuilder: (context, verticalPageIndex) {
returnContainer(
child: PageHorizontal(
verticalPageIndex: verticalPageIndex,
currentVertical: currentVertical,
currentVerticalPageDouble: currentVerticalPageDouble,
verticalIsOnPageTurning: verticalIsOnPageTurning,
setVerticalVisibility: (bool setVisibility){
if(setVisibility != verticalVisibility){
setState(() {
verticalVisibility = setVisibility;
});
}
},
setCurrentHorizontalPageDouble: (double val) {
if(currentHorizontalPageDouble != val) {
setState(() {
currentHorizontalPageDouble = val;
});
}
}
),
);
},
onPageChanged: (pageIndex) {
feedbackModel.setColindexRowIndex(colIndexP: pageIndex);
currentVertical = feedbackModel.pageControllerMain.page.toInt();
verticalIsOnPageTurning =false;
if(pageIndex == feedbackModel.playList.length) {
_scaffoldKey.currentState.showSnackBar(
CustomMessage.displaySnackBar(
'마지막 단어의 동영상 입니다'));
}
},
)),
//스크롤해도 안움직이는 영상들
Positioned(
top: 3.0.h,
right: 5.0.w,
child: feedbackModel.visibility
? Container(
padding: EdgeInsets.only(
left: 5, right: 5, top: 5, bottom: 5),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.5),
borderRadius: BorderRadius.circular(30),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Container(
child: Image.asset(
'assets/coin.png',
width: 20,
),
margin: EdgeInsets.only(right: 5),
),// fit: BoxFit.cover,
feedbackModel.userPoint !=null
? ValueListenableBuilder(
valueListenable:
feedbackModel.userPoint,
builder:
(context, int value, child) {
returnRow(
children: [
McCountingText(
begin: feedbackModel
.userPointRecord
.toDouble(),
end: value.toDouble(),
style: baseTextStyle()
.copyWith(
fontSize: 11.0.sp,
fontWeight:
FontWeight.bold,
),
duration:
Duration(seconds: 1),
curve: Curves.decelerate,
),
Text(
'P',
style: baseTextStyle()
.copyWith(
fontSize: 11.0.sp,
fontWeight:
FontWeight.bold,
),
),
],
);
},
)
: Text(
'0P ',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 11.0.sp),
),
// feedbackModel.userPoint != null ? Text('${feedbackModel.userPoint.value}P ', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 11.0.sp),
// ) : Text('0P ', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 11.0.sp),),
],
),
)
: Container(),
),
//포인트 없어졌다 나타내기
if(feedbackModel.showPluse.value)
Positioned(
right: 5.0.w,
top: 9.0.h,
child: AnimatedSwitcher(
duration: Duration(milliseconds: 50),
reverseDuration: Duration(milliseconds: 200),
transitionBuilder: (Widget child, Animation<double> animation) {
returnFadeTransition(opacity: animation, child: child);
},
child: Container(
key: ValueKey(feedbackModel.visibility),
child: feedbackModel.visibility
? Container(
height: 4.0.h,
width: 14.0.w,
decoration: BoxDecoration(
color: Colors.yellow.withOpacity(0.7),
// color: Colors.white.withOpacity(0.5),
borderRadius: BorderRadius.circular(30),
),
child: Center(
child: Text(
'+ 5P',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 11.0.sp, color: Colors.white),
)),
)
: Container(),
),
),
),
//점박이
Positioned(
left: 5.0.w,
child: feedbackModel.visibility
? Container(
child: SmoothPageIndicator(
// preloadController: feedbackModel.pageControllerMain,
controller: feedbackModel.pageControllerMain,
count: feedbackModel.playListUnviewd.keys.length,
axisDirection: Axis.vertical,
effect:ScrollingDotsEffect(
maxVisibleDots: 5,
spacing: 7.0,
radius: 30.0,
dotWidth: 15.0,
dotHeight: 5.0,
dotColor: Colors.black.withOpacity(0.2),
// fixedCenter: true,
// paintStyle: PaintingStyle.stroke,
strokeWidth: 0,
activeDotColor: Color(0xffbfff00),
),
),
)
: Container(),
),
],
);
},
),
);
}
}
classPageHorizontalextendsStatefulWidget {
PageHorizontal({
this.verticalPageIndex,
this.currentVertical,
this.currentVerticalPageDouble,
this.verticalIsOnPageTurning,
this.currentHorizontalPageIndex,
this.isPaused,
this.setVerticalVisibility,
this.setCurrentHorizontalPageDouble
});
finalint verticalPageIndex;
finalint currentVertical;
finaldouble currentVerticalPageDouble;
finalbool verticalIsOnPageTurning;
finalint currentHorizontalPageIndex;
finalbool isPaused;
finalFunction(bool) setVerticalVisibility;
finalFunction(double) setCurrentHorizontalPageDouble;
@override
_PageHorizontalState createState() => _PageHorizontalState();
}
class_PageHorizontalStateextendsState<PageHorizontal> {
double currentHoriDouble = 0;
int currentHorizontal = 0;
bool horizontalIsOnPageTurning =false;
// final _scaffoldKey = GlobalKey<ScaffoldState>();
PreloadPageController pageControllerHori;
// ScrollPhysics horizontalPreloadPhysics = new NeverScrollableScrollPhysics();
voidinitController2() {
// FeedbackProvider feedbackModel =
// Provider.of<FeedbackProvider>(context, listen: false);
FeedbackTabProvider feedbackModel = Provider.of<FeedbackTabProvider>(context, listen:false);
pageControllerHori =
// new PreloadPageController(initialPage: feedbackModel.playListReversed[widget.verticalPageIndex].length - 1);
newPreloadPageController(initialPage: feedbackModel.playListUnviewd.values.elementAt(widget.verticalPageIndex).length - 1);
setState(() {
// currentHorizontal = feedbackModel.playListReversed[widget.verticalPageIndex].length - 1;
currentHorizontal = feedbackModel.playListUnviewd.values.elementAt(widget.verticalPageIndex).length - 1;
});
varscrollListenerHori;
scrollListenerHori = () {
// print("scrollListenerHori - ${pageControllerHori.page},${pageControllerHori.position}");
/////////////////////////////////////////////
// horizontal blocking when loading is not done
/////////////////////////////////////////////
setState(() {
currentHoriDouble = pageControllerHori.page;
});
// called after image loading.
varcvIdx = widget.currentVerticalPageDouble.round();
varchIdx = pageControllerHori.page.round();
// var hMax = feedbackModel.playListReversed[cvIdx].length;
varhMax = feedbackModel.playListUnviewd.values.elementAt(cvIdx).length;
//현재 보고 있는 페이지를 기준으로 업데이트.
//어디로 로딩할지 모르기 때문에,상하좌우 전부 검사하여 하나라도 false이면 못움직이게 막음.
// min(), max()는 boundry check용
varright = feedbackModel.thumbnailLoadingIsDone[cvIdx][min(hMax - 1, chIdx + 1)];
varleft = feedbackModel.thumbnailLoadingIsDone[cvIdx][max(0, chIdx - 1)];
// print("ImageStreamListener - ${cvIdx},${vMax},${chIdx},${hMax}, ${up},${down},${right},${left}");
if((!(right[0] && right[1]) && pageControllerHori.page > pageControllerHori.page.round()) ||
(!(left[0] && left[1]) && pageControllerHori.page < pageControllerHori.page.round())) {
//우측이 아직 로딩되지 않았는데 가려고 하는 경우,혹은 좌측이 아직 로딩되지 않았는데 가려고 하느 경우.
//TODO:안넘어가는 조건부분 :로딩바 넣어주세요.
pageControllerHori.jumpToPage(chIdx.toInt());
}
if(horizontalIsOnPageTurning && pageControllerHori.page == pageControllerHori.page.roundToDouble()) {
setState(() {
currentHorizontal = pageControllerHori.page.toInt();
horizontalIsOnPageTurning =false;
});
}else if(!horizontalIsOnPageTurning && currentHorizontal.toDouble() != pageControllerHori.page) {
if((currentHorizontal.toDouble() - pageControllerHori.page).abs() > 0.7) {
setState(() {
horizontalIsOnPageTurning =true;
});
}
}
};
pageControllerHori.addListener(scrollListenerHori);
}
@override
voidinitState() {
super.initState();
initController2();
}
@override
voiddispose() {
// initController2();
super.dispose();
}
@override
Widget build(BuildContext context) {
FeedbackTabProvider feedbackModel = Provider.of<FeedbackTabProvider>(context);
if(widget.verticalIsOnPageTurning && currentHorizontal != feedbackModel.playListUnviewd.values.elementAt(widget.verticalPageIndex).length - 1) {
pageControllerHori.animateToPage(
feedbackModel.playListUnviewd.values.elementAt(widget.verticalPageIndex).length - 1,
duration: Duration(milliseconds: 300),
// curve: Curves.linear,
curve: Curves.linear,
);
}
returnPreloadPageView.builder(
controller: pageControllerHori,
scrollDirection: Axis.horizontal,
// itemCount: feedbackModel.playList[widget.verticalPageIndex].length,
itemCount: feedbackModel.playListUnviewd.values.elementAt(widget.verticalPageIndex).length,
preloadPagesCount: feedbackModel.playListUnviewd.values.elementAt(widget.verticalPageIndex).length,
// physics: horizontalPreloadPhysics,
// preloadPagesCount: 2,
itemBuilder: (context, horizontalPageIndex) {
returnContainer(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.black,
child: VideoApp(
// url: feedbackModel.playListReversed[widget.verticalPageIndex][pageIndexHori].feedback.url,
verticalPageIndex: widget.verticalPageIndex,
horizontalpageIndex: horizontalPageIndex,
currentVertical: widget.currentVertical,
currentHorizontal: currentHorizontal,
currentVerticalPageDouble: widget.currentVerticalPageDouble,
currentHoriDouble: currentHoriDouble,
verticalIsOnPageTurning: widget.verticalIsOnPageTurning,
horizontalIsOnPageTurning: horizontalIsOnPageTurning,
onButtonTapped: (int i) {
pageControllerHori.animateToPage(
i,
duration: Duration(milliseconds: 300),
curve: Curves.linear,
// curve: Curves.fastOutSlowIn,
);
},
resultFeedback: feedbackModel.playListUnviewd.values.elementAt(widget.verticalPageIndex)[horizontalPageIndex],
setVerticalVisibility: (bool setVerticalVisibility) {
widget.setVerticalVisibility(setVerticalVisibility);
},
),
);
},
onPageChanged: (pageIndexHori){
print('change change1');
feedbackModel.setColindexRowIndex(rowIndexP: pageIndexHori);
currentHorizontal = pageControllerHori.page.toInt();
// feedbackModel.rowIndex = pageIndexHori;
print('change change1 ${feedbackModel.rowIndex}');
},
);
}
}
classVideoAppextendsStatefulWidget {
VideoApp({
// this.url,
this.verticalPageIndex,
this.horizontalpageIndex,
this.currentVertical,
this.currentHorizontal,
this.verticalIsOnPageTurning,
this.horizontalIsOnPageTurning,
this.onButtonTapped,
this.resultFeedback,
this.setVerticalVisibility,
this.currentVerticalPageDouble,
this.currentHoriDouble
});
// final String url;
finalint verticalPageIndex;
finalint horizontalpageIndex;
finalint currentVertical;
finalint currentHorizontal;
finalbool verticalIsOnPageTurning;
finalbool horizontalIsOnPageTurning;
finalFunction(int) onButtonTapped;
finalfeedbacks.Results resultFeedback;
finalFunction(bool) setVerticalVisibility;
finaldouble currentVerticalPageDouble;
finaldouble currentHoriDouble;
@override
_VideoAppState createState() => _VideoAppState();
}
classVideoAppProgressIndicatorController {
voidFunction() adjust = () {};
voidFunction() play = () {};
voidFunction() stop = () {};
}
classVideoAppProgressIndicatorextendsStatefulWidget {
// VideoApp에서 사용하는 VideoProgressIndicator
// 1초마다 끊키는 것을
VideoAppProgressIndicator({
this.vapiController,
this.controller,
this.dur
});
finalVideoAppProgressIndicatorController vapiController;
finalVideoPlayerController controller;// pos, dur읽기 위한 controller
finalint dur;// duration in videocontroller
@override
_VideoAppProgressIndicatorState createState() => _VideoAppProgressIndicatorState();
}
class_VideoAppProgressIndicatorState
extendsState<VideoAppProgressIndicator>withSingleTickerProviderStateMixin {
// VideoAppProgressIndicator를 위한 State
varvideoPlayerControllerListener;
AnimationController controller;
int progress;
//최초 시작, pagemove로 인해 재시작,빨리감기/뒤로감기 클릭시
voidadjustProgress() {
int pos = widget.controller.value.position.inMilliseconds;// current
controller.value = pos.toDouble() / widget.dur.toDouble();//조정
progress = pos;
}
// play button
voidplay() {
controller.forward();
}
// stop button
voidstop() {
controller.stop();
}
@override
voidinitState() {
super.initState();
// controller method
widget.vapiController.adjust = adjustProgress;
widget.vapiController.play = play;
widget.vapiController.stop = stop;
// init
progress = 0;
controller = AnimationController(
vsync:this,
duration: Duration(milliseconds: widget.dur));
controller.stop();
// controller.value =
// listener를 통해 controller를 조정 변경.
videoPlayerControllerListener = () {
int pos = widget.controller.value.position.inMilliseconds;// current
//최신 progress갱신
progress = pos;
//재생되고 있는 상태:
//그 외에는 속도를 항상 재조정.
if(widget.dur - pos > 1000) {
// 1000초 이내일 경우에는 이 조정을 실시하지 않음.
// animation이 종료되지 않았는데 pos이 reset되어 돌아오는 경우가 있음.
//이를 방지하기 위함.
controller.animateTo(1,
duration: Duration(milliseconds: widget.dur - pos))
.whenComplete(() {
controller.reset();//리셋
//끝나면 자동으로 다시 재생.
if(widget.controller.value.isLooping) controller.forward();
});
}
};
widget.controller.addListener(videoPlayerControllerListener);
}
@override
voiddispose() {
widget.controller.removeListener(videoPlayerControllerListener);
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
varprogressLayout = LayoutBuilder(
builder: (context, constraints) {
returnAnimatedBuilder(
animation: controller,
child: Container(
width: constraints.maxWidth,
height: double.infinity,
color: Colors.white,
),
builder: (context, child) {
// only scale x
// print("builder - ${controller.value}, ${constraints.maxWidth}");
returnTransform(
transform: Matrix4.diagonal3Values(controller.value, 1.0, 1.0),
child: child);
},
);
}
);
varcontainer = Container(
width: double.infinity,
height: 5.0.h,
alignment: Alignment.centerLeft,
color: Colors.black.withOpacity(0.2),
child: progressLayout
);
returncontainer;
}
}
class_VideoAppStateextendsState<VideoApp> {
FeedbackTabProvider feedbackModel;
List<NetworkImage> thumbnails = [];
VideoPlayerController _controller;
bool initialized =false;
// bool favorate = false;
bool liked =false;
// bool loop = true;
final_scaffoldKey = GlobalKey<ScaffoldState>();
bool showPluse =false;
int viewedInt = 0;
int likedInt = 0;
VideoAppProgressIndicatorController vapiController;
// bool panelOpened = false;
finalValueNotifier<bool> panelOpened = ValueNotifier<bool>(false);
voidinitController() {
vapiController = VideoAppProgressIndicatorController();
_controller = VideoPlayerController.network(
widget.resultFeedback.feedback.url,
);
_controller.initialize().then((value) {
setState(() {
initialized =true;
if(feedbackModel.loop){
_controller.setLooping(true);
}
// _controller.setLooping(true);
// feedbackModel.loop = true;
// urlSaved = widget.url;
});
//비디오 로딩 완료 마킹
varvIdx = widget.verticalPageIndex;
varhIdx = widget.horizontalpageIndex;
//내 것을 true로 설정.
// feedbackModel.thumbnailLoadingIsDone[vIdx][hIdx][1] = true;
// print("thumbnailLoadingIsDone[${vIdx}][${hIdx}] = true");
varplayListener;
playListener = () {
int dur = _controller.value.duration.inMilliseconds;
int pos = _controller.value.position.inMilliseconds;
if(!feedbackModel.thumbnailLoadingIsDone[vIdx][hIdx][1]
&& dur > 0 && pos == 0) {
//내 것을 true로 설정.
feedbackModel.thumbnailLoadingIsDone[vIdx][hIdx][1] =true;
}
// if(feedbackModel.panelController.isPanelOpen && !panelOpened){
// print('열림 열림 열림 열림 열림 열림 열림 열림 열림 열림 열림 ');
// setState(() {
// panelOpened = true;
// });
// } else if (feedbackModel.panelController.isPanelClosed && panelOpened){
// print('닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 ');
// setState(() {
// panelOpened = false;
// });
// }
// NOTE: panelOpened값이 playListener안에 있는것이 어색해서
// build()로 빼두었습니다.잘못된 것이라면 수정 부탁드립니다(By Kyoseung).
if(dur - pos < 400) {
if(feedbackModel.playListUnviewd.values.elementAt(widget.verticalPageIndex)[widget.horizontalpageIndex].viewed ==false){
feedbackModel.setShowPluse(true);
setState(() {
showPluse =true;
viewedInt += 1;
});
feedbackModel.setView(feedbackModel.playListUnviewd.keys.elementAt(widget.verticalPageIndex), widget.horizontalpageIndex, widget.verticalPageIndex);
ApiAdapter.patchFeedback(widget.resultFeedback.id, viewed:true).then((value) {
if(value == 200){
print('ok ok ok ok ok');
feedbackModel.setPoint();
}
});
// .then((value) {
// print('ok ok ok ok ok');
// feedbackModel.setPoint();
print('ok2 ok2 ok2 ok2 ok2');
// Timer(Duration(milliseconds: 500), () {
setState(() {
//바텀네비 숫자제어
Provider.of<TabPageProvider>(context, listen:false).setCounterForFeedback(1);
// feedbackModel.setShowPluse(false);
// showPluse = false;
print('ok3 ok3 ok3 ok3 ok3');
feedbackModel.setPointRecord(feedbackModel.userPoint.value);
});
// });
Timer(Duration(seconds: 2), () {
feedbackModel.setShowPluse(false);
});
print('TabPageProvider TabPageProvider TabPageProvider ${Provider.of<TabPageProvider>(context, listen:false).counterForFeedback.value}');
if(Provider.of<TabPageProvider>(context, listen:false).counterForFeedback.value == 0){
_showDialog();
}
}
// if (feedbackModel.playList[widget.verticalPageIndex][widget.horizontalpageIndex].viewed == false) {
// feedbackModel.setShowPluse(true);
// setState(() {
// showPluse = true;
// viewedInt += 1;
// });
//
//
// feedbackModel.setView(widget.verticalPageIndex, widget.horizontalpageIndex);
// ApiAdapter.patchFeedback(widget.resultFeedback.id, viewed: true).then((value) {
// if(value == 200){
// print('ok ok ok ok ok');
// feedbackModel.setPoint();
// }
// });
// // .then((value) {
// // print('ok ok ok ok ok');
// // feedbackModel.setPoint();
// print('ok2 ok2 ok2 ok2 ok2');
// // Timer(Duration(milliseconds: 500), () {
// setState(() {
// //바텀네비 숫자제어
// Provider.of<TabPageProvider>(context, listen: false).setCounterForFeedback(1);
// // feedbackModel.setShowPluse(false);
// // showPluse = false;
// print('ok3 ok3 ok3 ok3 ok3');
// feedbackModel.setPointRecord(feedbackModel.userPoint.value);
// });
// // });
// Timer(Duration(seconds: 2), () {
// feedbackModel.setShowPluse(false);
// });
// print('TabPageProvider TabPageProvider TabPageProvider ${Provider.of<TabPageProvider>(context, listen: false).counterForFeedback.value}');
// if(Provider.of<TabPageProvider>(context, listen: false).counterForFeedback.value == 0){
// _showDialog();
// }
// }
if(feedbackModel.loop) {
_controller.setLooping(true);
}
if(!feedbackModel.loop) {
//마지막 비디오가아닐때
if(widget.verticalPageIndex < feedbackModel.playList.length - 1){
feedbackModel.pageControllerMain.animateToPage(widget.verticalPageIndex + 1,
duration: Duration(milliseconds: 300),
// curve: Curves.easeIn
curve: Curves.linear,
);
}else{
_controller.setLooping(true);
}
}
}
};
_controller.addListener(playListener);
});
}
voidinitThumbnails() {
// build()시마다 listener붙는 것을 방지하기 위해 미리 생성함.
for(vari = 0; i < feedbackModel.playListUnviewd.values.elementAt(widget.verticalPageIndex).length; i++) {
varthumbnailImage = NetworkImage('${feedbackModel.playListUnviewd.values.elementAt(widget.verticalPageIndex)[i].feedback.thumbnail}');
thumbnailImage.resolve(ImageConfiguration())
.addListener(ImageStreamListener(
(info, call) {
// called after image loading.
varvIdx = widget.verticalPageIndex;
varhIdx = i;
//내 것을 true로 설정.
feedbackModel.thumbnailLoadingIsDone[vIdx][hIdx][0] =true;
print("thumbnailLoadingIsDone[${vIdx}][${hIdx}] = true");
}
));
thumbnails.add(thumbnailImage);
}
}
@override
voidinitState() {
super.initState();
feedbackModel = Provider.of<FeedbackTabProvider>(context, listen:false);
initController();
getFavorate();
getLike();
setViewLike();
// initialize thumbnail networkimage
initThumbnails();
//포임트
// getPoint();
// getViewed();
WidgetsBinding.instance.addPostFrameCallback((_) {});
}
//포인트 반아오기
// getPoint() async {
// userId = SharedPrefs().userId;
// // int _selectedBookId = SharedPrefs().bookId;
// //현제 포인트
// GetPoint getPoint = await ApiAdapter.getUserPoint(userId);
// if (mounted) {
// setState(() {
// _getPoint = getPoint;
// userPoint = getPoint.pointResults.first.amount;
// });
// }
// }
setViewLike() {
if(widget.resultFeedback !=null) {
setState(() {
viewedInt = widget.resultFeedback.feedback.view;
likedInt = widget.resultFeedback.feedback.like;
});
}
}
getFavorate()async{
if(widget.resultFeedback.saved) {
// setState(() {
feedbackModel.favorate =true;
// });
}else{
// setState(() {
feedbackModel.favorate =false;
// });
}
}
getLike()async{
if(widget.resultFeedback.liked) {
setState(() {
liked =true;
});
}else{
setState(() {
liked =false;
});
}
}
@override
voiddispose() {
//비디오 로딩 취소 마킹
varvIdx = widget.verticalPageIndex;
varhIdx = widget.horizontalpageIndex;
//내 것을 false로 설정.
// feedbackModel.thumbnailLoadingIsDone[vIdx][hIdx][1] = false;
// feedbackModel.thumbnailLoadingIsDone[vIdx][hIdx][0] = false;
// print("thumbnailLoadingIsDone[${vIdx}][${hIdx}] = false");
// print("thumbnailLoadingIsDone[${vIdx}][${hIdx}] = false");
// _controller.dispose();
super.dispose();
_controller.pause();
_controller?.dispose();
}
voidupdatePanelOpened() {
if(playerExpandProgress.value > 80 && !panelOpened.value && widget.verticalPageIndex == widget.currentVertical
&& widget.horizontalpageIndex == widget.currentHorizontal){
_controller.pause();
print('열림 열림 열림 열림 열림 열림 열림 열림 열림 열림 열림 ');
// setState(() {
panelOpened.value =true;
//페넬 열렸을때 비디오 멈추기
// _controller.pause();
// });
// _controller.pause();
}else if(playerExpandProgress.value < 80 && panelOpened.value && widget.verticalPageIndex == widget.currentVertical
&& widget.horizontalpageIndex == widget.currentHorizontal){
print('닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 닫힘 ');
// setState(() {
panelOpened.value =false;
//페넬 닫혔을때 비디오 시작
_controller.play();
// });
}
}
@override
Widget build(BuildContext context) {
//build바로 밑에 setState가 될만한게있음 에러
// Future.delayed(Duration.zero, () async {
updatePanelOpened();
// });
if(widget.verticalPageIndex == widget.currentVertical
&& widget.horizontalpageIndex == widget.currentHorizontal
&& !widget.verticalIsOnPageTurning
&& !widget.horizontalIsOnPageTurning
&& initialized
&& !panelOpened.value
//아래 조건 2개는 완전히 페이지가 정지했는지를 판별하기 위함.
&& (widget.currentVerticalPageDouble == widget.currentVerticalPageDouble.toInt())
&& (widget.currentHoriDouble == widget.currentHoriDouble.toInt())
) {
_controller.play();
}else{
if(widget.verticalPageIndex != widget.currentVertical
|| widget.horizontalpageIndex != widget.currentHorizontal
&& panelOpened.value
// && playerExpandProgress.value > 80
&& initialized) {
_controller.pause();
_controller.seekTo(Duration(milliseconds: 0));
vapiController.adjust();
vapiController.stop();
}else{
_controller.pause();
vapiController.stop();
}
}
// });
returnScaffold(
key: _scaffoldKey,
body: !_controller.value.initialized
// && _getPoint == null
? Stack(
children: [
Container(
color: Colors.black87,
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
),
Positioned(
top: 0,
child: Container(
padding: EdgeInsets.only(left: 10, right: 10, top: 40, bottom: 5),
height: 16.0.h,
width: MediaQuery.of(context).size.width,
color: Colors.black.withOpacity(0.5),
// color: Colors.grey,
),
),
Positioned(
// bottom: 8.0.h,
// height: 12.7.h,
bottom: 0,
height: 12.7.h,
child: Container(
padding: EdgeInsets.only(left: 20, right: 20, top: 20, bottom: 20),
width: MediaQuery.of(context).size.width,
color: Colors.black.withOpacity(0.5),
// color: Colors.grey,
),
),
Positioned(
// bottom: 20.0.h,
// left: 0,
// right: 0,
bottom: 12.0.h,
left: 0,
right: 0,
child: LinearProgressIndicator(
backgroundColor: Colors.black12,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white30),
),
),
],
)
: Stack(
children: <Widget>[
Container(
color: Colors.black,
child: Center(
child: AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: Center(child: VideoPlayer(_controller)),
),
),
),
_playControll(),
],
),
);
}
Widget _playControll() {
finaldouble statusBarHeight = MediaQuery.of(context).padding.top;
finaldouble bottomBarHeight = MediaQuery.of(context).padding.bottom;
// print('hohohohohoho ${_controller.value.duration.inMilliseconds}');
// print('hohohohohoho ${_controller.value.duration.inMicroseconds}');
// print('hohohohohoho ${_controller.value.position.inMilliseconds}');
// print('hohohohohoho ${_controller.value.position.inMicroseconds}');
// print('hohohohohoho ${_controller.value.duration}');
// print('_playControll() - statusBarHeight=${statusBarHeight},bottomBarHeight=${bottomBarHeight}');
returnContainer(
color: Colors.transparent,
child: !_controller.value.initialized
? Container(color: Colors.transparent)
: Stack(
children: [
///화면 탭 인지 부분
Positioned(
top: statusBarHeight,
child: GestureDetector(
onTap: () {
// _controller.pause();
// _showDialog();
print("tap");
print("visibility : ${feedbackModel.visibility.toString()}");
// if (feedbackModel.panelController.isPanelOpen) feedbackModel.panelController.close();
if(mounted) {
setState(() {
feedbackModel.cancelTimer();
feedbackModel.setVisibility(!feedbackModel.visibility);
widget.setVerticalVisibility(feedbackModel.visibility);
// if (_controller.value.isPlaying) {
// feedbackModel
// .setTimer(Timer(Duration(seconds: 3), () {
// if (_controller.value.isPlaying) {
// if (mounted) {
// setState(() {
// feedbackModel.setVisibility(false);
// });
// }
// }
// }));
// }
});
}
},
child: Container(
color: Colors.transparent,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height - statusBarHeight - 40.h,
// width: 100.0.w,
// height: 40.0.h,
),
),
),
///exit버튼,단계버튼
Positioned(
top: 0,
child: AnimatedSwitcher(
duration: Duration(milliseconds: 50),
reverseDuration: Duration(milliseconds: 200),
transitionBuilder: (Widget child, Animation<double> animation) {
returnFadeTransition(opacity: animation, child: child);
},
child: Container(
key: ValueKey(feedbackModel.visibility),
child: feedbackModel.visibility
? Container(
padding: EdgeInsets.only(left: 5.0.w, right: 5.0.w),
width: 100.0.w,
color: Colors.black.withOpacity(0.2),
child: Column(
children: [
SizedBox(height: 10.0.h,),
Container(
height: 10.0.h,
width: MediaQuery.of(context).size.width,
child: ListView.builder(
itemCount: feedbackModel.playListUnviewd.values.elementAt(widget.verticalPageIndex).length,
shrinkWrap:true,
scrollDirection: Axis.horizontal,
itemBuilder: (context, position) {
if(position == widget.horizontalpageIndex) {
returnPadding(
padding:constEdgeInsets.only(left: 10.0),
child: Column(
children: [
Container(
child: FittedBox(
fit: BoxFit.contain,
child: CircleAvatar(
radius: 30.sp,
backgroundColor: feedbackModel
.playListUnviewd.values.elementAt(widget.verticalPageIndex)[position]
.viewed
? Colors.transparent
: Colors.redAccent,
child: CircleAvatar(
backgroundColor: Colors.transparent,
backgroundImage: thumbnails[position],
radius: feedbackModel
.playListUnviewd.values.elementAt(widget.verticalPageIndex)[position]
.viewed
? 30.sp
: 28.sp,
child: Stack(
children: [
Visibility(
child: Container(
width: 10.0.w,
// height: 5.0.h,
child: Center(
child:
Lottie.asset("assets/play_button.json",
width: 100, repeat:true, fit: BoxFit.cover),
// Icon(
// Icons.play_circle_fill,
// color: Colors.red,
// size: 10.0.w,
// ),
),
)),
],
),
),
),
),
),
Expanded(
child: Text(
'${position + 1}단계',
style: TextStyle(
color: Colors.white,
),
),
),
],
),
);
}else{
returnInkWell(
onTap: () {
widget.onButtonTapped(position);
},
child: Padding(
padding:constEdgeInsets.only(left: 10.0),
child: Column(
children: [
Container(
child: CircleAvatar(
radius: 30.sp,
backgroundColor: feedbackModel
.playListUnviewd.values.elementAt(widget.verticalPageIndex)[position]
.viewed
? Colors.transparent
: Colors.redAccent,
child: CircleAvatar(
backgroundColor: Colors.transparent,
backgroundImage: thumbnails[position],
radius: feedbackModel
.playListUnviewd.values.elementAt(widget.verticalPageIndex)
[position]
.viewed
? 30.sp
: 28.sp,
),
),
),
Expanded(
child: Text(
'${position + 1}단계',
style: TextStyle(
color: Colors.white,
),
),
),
],
),
));
}
},
)),
],
),
)
: Container(),
),
),
),
///play, prev, next버튼 영역
Positioned(
child: Center(
child: AnimatedSwitcher(
duration: Duration(milliseconds: 50),
reverseDuration: Duration(milliseconds: 200),
transitionBuilder: (Widget child, Animation<double> animation) {
returnFadeTransition(opacity: animation, child: child);
},
child: Container(
key: ValueKey(feedbackModel.visibility),
width: double.infinity,
child: feedbackModel.visibility
?
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Material(
color: Colors.transparent,
child: InkWell(
customBorder: CircleBorder(),
onTap: ()async{
await_controller.seekTo(await_controller.position - Duration(seconds: 3));
// indicator재조정
vapiController.adjust();
},
child: Padding(
padding:constEdgeInsets.all(15),
child: Image.asset(
'assets/rewind.png',
width: 15.0.w,
color: Colors.black.withOpacity(0.2),
),
),
),
),
Container(width: 10,),
Material(
color: Colors.transparent,
child: InkWell(
customBorder: CircleBorder(),
onTap: () {
if(mounted) {
if(_controller.value.isPlaying) {
_controller.pause();
setState(() {
initialized =false;
});
feedbackModel.cancelTimer();
feedbackModel.setVisibility(true);
// stop indicator
vapiController.stop();
}else{
if(_controller.value.position == _controller.value.duration) {
_controller.initialize();
setState(() {
initialized =true;
});
_controller.play();
}else{
setState(() {
initialized =true;
});
_controller.play();
}
feedbackModel.setTimer(Timer(Duration(seconds: 3), () {
if(_controller.value.isPlaying)if(mounted) {
setState(() {
feedbackModel.setVisibility(false);
});
}
}));
// start indicator
vapiController.play();
}
}
},
child: Padding(
padding:constEdgeInsets.all(15),
child: Icon(
_controller.value.isPlaying ? Icons.pause: Icons.play_arrow,
color: Colors.black.withOpacity(0.2),
size: 15.0.w,
),
)),
),
Container(width: 10,),
Material(
color: Colors.transparent,
child: InkWell(
customBorder: CircleBorder(),
onTap: ()async{
if(_controller.value.duration - _controller.value.position <
Duration(seconds: 6)) {
await_controller.seekTo(Duration.zero);
}else{
await_controller.seekTo(await_controller.position + Duration(seconds: 3));
}
// indicator재조정
vapiController.adjust();
},
child: Padding(
padding:constEdgeInsets.all(15),
child: Image.asset(
'assets/forward.png',
width: 15.0.w,
color: Colors.black.withOpacity(0.2),
),
),
),
),
],
)
: Container(),
),
),
),
),
//viewd랑 좋아요
Positioned(
bottom: 22.0.h,
right: 2.0.w,
// bottom: 20.0.h,
child: AnimatedSwitcher(
duration: Duration(milliseconds: 50),
reverseDuration: Duration(milliseconds: 200),
transitionBuilder: (Widget child, Animation<double> animation) {
returnFadeTransition(opacity: animation, child: child);
},
child: Container(
key: ValueKey(feedbackModel.visibility),
child: feedbackModel.visibility
? Container(
width: 100.0.w,
height: 25.0.h,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(
icon: Icon(
Icons.visibility, color: Colors.white,
),
iconSize: 8.0.w
// fit: BoxFit.cover,
),
Container(
width: 8.0.w,
child: Center(
child: Text(
'$viewedInt',
style: TextStyle(color: Colors.white, fontSize: 12.0.sp),
),
),
),
SizedBox(
height: 1.0.h,
),
InkWell(
onTap: () {
// feedbackModel.setliked(widget.resultFeedback.id, liked, widget.verticalPageIndex, widget.horizontalpageIndex);
if(liked) {
feedbackModel.setliked(widget.resultFeedback.id,false,
widget.verticalPageIndex, widget.horizontalpageIndex);
setState(() {
liked = !liked;
likedInt -= 1;
});
_scaffoldKey.currentState
.showSnackBar(CustomMessage.displaySnackBar('좋아요 영상에서 해제되었습니다'));
}else{
feedbackModel.setliked(widget.resultFeedback.id,true,
widget.verticalPageIndex, widget.horizontalpageIndex);
setState(() {
liked = !liked;
likedInt += 1;
});
_scaffoldKey.currentState
.showSnackBar(CustomMessage.displaySnackBar('영상이 좋아요에 등록이 되었습니다'));
}
},
child:
IconButton(
icon:
!liked ? Icon(Icons.favorite_border_outlined,
color: Colors.white,) : Icon(
Icons.favorite_outlined, color: Colors.white,
),
iconSize: 8.0.w
// fit: BoxFit.cover,
)
),
Container(
width: 8.0.w,
child: Center(
child: Text(
'$likedInt',
style: TextStyle(color: Colors.white, fontSize: 12.0.sp),
),
),
),
],
),
],
),
)
: Container(),
),
)),
//로딩
if(_controller.value.initialized &&
_controller.value.duration.inMilliseconds > 0)
Positioned(
bottom: 20.0.h,
// bottom: 12.0.h,
child: AnimatedContainer(
duration: Duration(milliseconds: 50),
child: Opacity(
opacity: feedbackModel.visibility && !feedbackModel.pageMoving.value ? 1 : 0,
child: Container(
child: Padding(
padding:constEdgeInsets.symmetric(vertical: 4),
child: Container(
height: 1,
// height: 37,
width: MediaQuery.of(context).size.width,
child: VideoAppProgressIndicator(
vapiController: vapiController,
controller: _controller,
dur: _controller.value.duration.inMilliseconds
),
),
),
),
)
)),
//시간표시
if(!feedbackModel.pageMoving.value)
Positioned(
bottom: 21.0.h,
right: 0,
// bottom: 13.0.h,
// right: 0,
child: AnimatedSwitcher(
duration: Duration(milliseconds: 50),
reverseDuration: Duration(milliseconds: 200),
transitionBuilder: (Widget child, Animation<double> animation) {
returnFadeTransition(opacity: animation, child: child);
},
child: Container(
key: ValueKey(feedbackModel.visibility),
child: feedbackModel.visibility
? ValueListenableBuilder(
valueListenable: _controller,
builder: (context, VideoPlayerValue value, child) {
Duration millis = value.duration - value.position;
varseconds = millis.inSeconds;
finaldays = seconds ~/ Duration.secondsPerDay;
seconds -= days * Duration.secondsPerDay;
finalhours = seconds ~/ Duration.secondsPerHour;
seconds -= hours * Duration.secondsPerHour;
finalminutes = seconds ~/ Duration.secondsPerMinute;
seconds -= minutes * Duration.secondsPerMinute;
finalList<String> tokens = [];
if(days != 0) {
tokens.add('${days}d');
}
if(tokens.isNotEmpty || hours != 0) {
tokens.add('${hours}h');
}
if(tokens.isNotEmpty || minutes != 0) {
tokens.add('${minutes}m');
}
tokens.add('${seconds}s');
//타이머 투명처리
returnText(
tokens.join(':').toString(),
style: TextStyle(color: Colors.transparent, fontSize: 12),
);
},
)
: Container(),
),
)),
],
),
);
}
Future<bool> onLikeButtonTapped(bool isLiked)async{
if(liked) {
feedbackModel.setliked(widget.resultFeedback.id,false,
widget.verticalPageIndex, widget.horizontalpageIndex);
setState(() {
liked = !liked;
likedInt -= 1;
});
_scaffoldKey.currentState
.showSnackBar(CustomMessage.displaySnackBar('좋아요 영상에서 해제되었습니다'));
}else{
feedbackModel.setliked(widget.resultFeedback.id,true,
widget.verticalPageIndex, widget.horizontalpageIndex);
setState(() {
liked = !liked;
likedInt += 1;
});
_scaffoldKey.currentState
.showSnackBar(CustomMessage.displaySnackBar('영상이 좋아요에 등록이 되었습니다'));
}
return!isLiked;
}
void_showDialog() {
finalfeedbackModel = Provider.of<FeedbackTabProvider>(context, listen:false);
showDialog(
context: context,
barrierDismissible:false,
builder: (BuildContext context) {
returnAlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
content: SingleChildScrollView(
child: Column(
children: [
Padding(
padding:constEdgeInsets.symmetric(vertical: 10.0),
child: Container(height: 6.0.h, child: Image.asset("assets/coin.png")),
),
Container(
height: 10.h,
),
Text(
"총 ${feedbackModel.unviewCount * 5}포인트 획득",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 13.0.sp,
fontWeight: FontWeight.bold,
),
),
Text(
"영상을 모두 시청하였어요!",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 13.0.sp,
),
),
],
),
),
actions: <Widget>[
SizedBox(
width: MediaQuery.of(context).size.width,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.grey[300],
onPrimary: Colors.black,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32.0),
),
),
child: Container(
width: 20.0.w,
child: Center(
child: Text(
"계속 보기",
style: TextStyle(
fontSize: 15.sp,
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
),
onPressed: () {
Navigator.pop(context);
setState(() {
initialized =true;
});
},
),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.black,
onPrimary: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32.0),
),
),
child: Container(
width: 20.0.w,
child: Center(
child: Text(
"홈으로",
style: TextStyle(
fontSize: 15.sp,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
onPressed: () {
if(_controller.value.isPlaying) _controller.pause();
if(initialized =true) {
setState(() {
initialized =false;
});
}
Navigator.pushReplacement<void,void>(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) => TabPage(),
),
);
// setState(() {
// _controller = null;
// });
},
),
],
),
),
],
);
},
);
}
}