From 4ab8fab39b30391279d9af968578c0d34e35749a Mon Sep 17 00:00:00 2001 From: TSLA Coin <6106454+TelsaV@users.noreply.github.com> Date: Sun, 27 Mar 2022 23:17:48 +0800 Subject: [PATCH] add discover module --- lib/Screens/home/home.dart | 182 ++++++++++++------ lib/Screens/login/login.dart | 2 + lib/Screens/search/challenge_item.dart | 80 ++++++++ lib/Screens/search/music_item.dart | 111 +++++++++++ lib/Screens/search/search.dart | 9 +- lib/Screens/search/user_item.dart | 77 ++++++++ lib/api/api.dart | 19 ++ lib/models/dto/discover/banner_dto.dart | 6 + .../dto/discover/discover_challenge_dto.dart | 6 +- .../dto/discover/discover_music_dto.dart | 6 +- .../dto/discover/discover_user_dto.dart | 6 +- lib/models/vo/discover/banner_vo.dart | 8 + lib/models/vo/discover/discover_music_vo.dart | 114 ++++++++++- 13 files changed, 556 insertions(+), 70 deletions(-) create mode 100644 lib/Screens/search/challenge_item.dart create mode 100644 lib/Screens/search/music_item.dart create mode 100644 lib/Screens/search/user_item.dart create mode 100644 lib/models/dto/discover/banner_dto.dart create mode 100644 lib/models/vo/discover/banner_vo.dart diff --git a/lib/Screens/home/home.dart b/lib/Screens/home/home.dart index 240cf48..137c1f2 100644 --- a/lib/Screens/home/home.dart +++ b/lib/Screens/home/home.dart @@ -41,9 +41,8 @@ class _Home extends State with SingleTickerProviderStateMixin { bool isLogin = false; late VideoPlayerController _controller; ItemListDto dto = new ItemListDto(0, 20); - //late VideoPlayerController _musicController; - //late AnimationController animationController; - late Future videos; + late Future foryouVideos; + late Future followingVideos; PageController pageController = PageController(initialPage: 0, viewportFraction: 0.8); // ScrollController _scrollController = ScrollController(initialScrollOffset:0); @@ -56,8 +55,8 @@ class _Home extends State with SingleTickerProviderStateMixin { @override void initState() { super.initState(); - videos = Api.getRecommendItemList(dto); - + foryouVideos = Api.getRecommendItemList(dto); + followingVideos = Api.getFollowingItemList(dto); _controller = VideoPlayerController.network( "http://appmedia.qq.com/media/cross/assets/uploadFile/20170523/5923d26dac66b.mp4") ..initialize(); @@ -153,7 +152,7 @@ class _Home extends State with SingleTickerProviderStateMixin { if (foryou) { _controller.pause(); return FutureBuilder( - future: videos, + future: foryouVideos, builder: (context, snapshot) { print(snapshot.connectionState); if (snapshot.connectionState == ConnectionState.waiting) { @@ -208,60 +207,123 @@ class _Home extends State with SingleTickerProviderStateMixin { }); } else { _controller.play(); - return Container( - width: double.infinity, - height: double.infinity, - color: Colors.black, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - padding: EdgeInsets.only(bottom: 14), - child: Text( - 'Trendy creators', - style: TextStyle(color: Colors.white, fontSize: 20), - )) - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Center( - child: Container( - child: Column( - children: [ - Center( - child: Text('Follow to an account to discover its', - style: TextStyle( - color: Colors.white.withOpacity(0.8))), - ), - Center( - child: Text('Latest videos here.', - style: TextStyle( - color: Colors.white.withOpacity(0.8))), - ) - ], - ), - ), - ) - ], - ), - Container( - height: 372, - margin: EdgeInsets.only(top: 25), - child: PageView.builder( - dragStartBehavior: DragStartBehavior.down, - controller: pageController, - itemCount: 5, - itemBuilder: (context, position) { - return videoSlider(position); - }), - ) - ], - )); + return FutureBuilder( + future: followingVideos, + builder: (context, snapshot) { + print(snapshot.connectionState); + if (snapshot.connectionState == ConnectionState.waiting) { + return loading; + } else if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.hasError) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height - 24, + color: Colors.black, + child: Center( + child: Text( + 'Error, Please restart your app again.', + style: TextStyle(color: Colors.white), + )), + ) + ], + ); + } else if (snapshot.hasData) { + try { + return PageView.builder( + controller: foryouController, + onPageChanged: (index) { + //when the video is changing, release the previous video instance. + //disposeVideo(); + //setState(() {}); + }, + scrollDirection: Axis.vertical, + itemCount: snapshot.data!.itemList!.length, + itemBuilder: (context, index) { + var item = snapshot.data!.itemList![index]; + return Videoplayer( + item: item, + width: MediaQuery.of(context).size.width, + heigth: MediaQuery.of(context).size.height, + ); + }); + } catch (e) { + return Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + color: Colors.black, + child: Center( + child: Text( + 'Error, Please restart your app again.', + style: TextStyle(color: Colors.white), + )), + ); + } + } else { + // empty data + return loading; + } + } else { + return Text('State: ${snapshot.connectionState}'); + } + }); + // return Container( + // width: double.infinity, + // height: double.infinity, + // color: Colors.black, + // child: Column( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // Row( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // Container( + // padding: EdgeInsets.only(bottom: 14), + // child: Text( + // 'Trendy creators', + // style: TextStyle(color: Colors.white, fontSize: 20), + // )) + // ], + // ), + // Row( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // Center( + // child: Container( + // child: Column( + // children: [ + // Center( + // child: Text('Follow to an account to discover its', + // style: TextStyle( + // color: Colors.white.withOpacity(0.8))), + // ), + // Center( + // child: Text('Latest videos here.', + // style: TextStyle( + // color: Colors.white.withOpacity(0.8))), + // ) + // ], + // ), + // ), + // ) + // ], + // ), + // Container( + // height: 372, + // margin: EdgeInsets.only(top: 25), + // child: PageView.builder( + // dragStartBehavior: DragStartBehavior.down, + // controller: pageController, + // itemCount: 5, + // itemBuilder: (context, position) { + // return videoSlider(position); + // }), + // ) + // ], + // )); } } // Home Screen Code end diff --git a/lib/Screens/login/login.dart b/lib/Screens/login/login.dart index e92f6b7..ba63544 100644 --- a/lib/Screens/login/login.dart +++ b/lib/Screens/login/login.dart @@ -14,6 +14,7 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:telsavideo/api/api.dart'; import 'package:telsavideo/components/api.dart'; import 'package:telsavideo/constants.dart'; +import 'package:telsavideo/http/base/base_domain.dart'; import 'package:telsavideo/http/util.dart'; import 'package:telsavideo/models/dto/signin/signin_dto.dart'; import 'package:telsavideo/models/vo/signin/signin_vo.dart'; @@ -62,6 +63,7 @@ class _LoginState extends State { SignInVo result = await Api.postLoginResponse(dto); print(result); Util.set('isLogin', true); + Util.set(BaseDomain.xUSERTOKEN, result.accessToken); Util.set("dtok_accessToken", result.accessToken); Util.set("dtok_token_expire", result.expiresInDate); Util.set("dtok_refreshToken", result.refreshToken); diff --git a/lib/Screens/search/challenge_item.dart b/lib/Screens/search/challenge_item.dart new file mode 100644 index 0000000..809a593 --- /dev/null +++ b/lib/Screens/search/challenge_item.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; +import 'package:telsavideo/api/api.dart'; +import 'package:telsavideo/models/dto/discover/discover_challenge_dto.dart'; +import 'package:telsavideo/models/dto/discover/discover_music_dto.dart'; +import 'package:telsavideo/models/vo/discover/discover_challenage_vo.dart'; +import 'package:telsavideo/screens/loading/loading.dart'; + +class ChallengeItem extends StatefulWidget { + @override + State createState() { + // TODO: implement createState + throw UnimplementedError(); + } +} + +class _ChallengeItemState extends State { + DiscoverChallengeDto dto = new DiscoverChallengeDto(0, 20); + + late Future getDiscoverChallenges; + @override + void initState() { + // TODO: implement initState + super.initState(); + getDiscoverChallenges = Api.getDiscoverChanllenge(dto); + } + + @override + Widget build(BuildContext context) { + // TODO: implement build + double width = MediaQuery.of(context).size.width; + return FutureBuilder( + future: getDiscoverChallenges, + builder: (context, snapshot) { + print(snapshot.connectionState); + if (snapshot.connectionState == ConnectionState.waiting) { + return loading; + } else if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.hasError) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height - 24, + color: Colors.black, + child: Center( + child: Text( + 'Error, Please restart your app again.', + style: TextStyle(color: Colors.white), + )), + ) + ], + ); + } else if (snapshot.hasData) { + try { + return Container(); + } catch (e) { + return Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + color: Colors.black, + child: Center( + child: Text( + 'Error, Please restart your app again.', + style: TextStyle(color: Colors.white), + )), + ); + } + } else { + // empty data + return loading; + } + } else { + return Text('State: ${snapshot.connectionState}'); + } + }, + ); + } +} diff --git a/lib/Screens/search/music_item.dart b/lib/Screens/search/music_item.dart new file mode 100644 index 0000000..3b2288d --- /dev/null +++ b/lib/Screens/search/music_item.dart @@ -0,0 +1,111 @@ +import 'dart:ffi'; + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:telsavideo/api/api.dart'; +import 'package:telsavideo/models/dto/discover/discover_music_dto.dart'; +import 'package:telsavideo/models/vo/discover/discover_music_vo.dart'; +import 'package:telsavideo/screens/loading/loading.dart'; + +class MusicItem extends StatefulWidget { + @override + _MusicItemState createState() => _MusicItemState(); +} + +class _MusicItemState extends State { + late Future getDiscoverMusics; + + DiscoverMusicDto dto = new DiscoverMusicDto(0, 10); + + @override + void initState() { + // TODO: implement initState + super.initState(); + getDiscoverMusics = Api.getDiscoverMusic(dto); + } + + @override + Widget build(BuildContext context) { + // TODO: implement build + double width = MediaQuery.of(context).size.width; + return FutureBuilder( + future: getDiscoverMusics, + builder: (context, snapshot) { + print(snapshot.connectionState); + if (snapshot.connectionState == ConnectionState.waiting) { + return loading; + } else if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.hasError) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height - 24, + color: Colors.black, + child: Center( + child: Text( + 'Error, Please restart your app again.', + style: TextStyle(color: Colors.white), + )), + ) + ], + ); + } else if (snapshot.hasData) { + try { + return Container( + width: width, + height: 100.0, + child: ListView.builder( + itemCount: snapshot.data!.musicInfoList.length, + scrollDirection: Axis.horizontal, + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + final length = snapshot.data!.musicInfoList.length; + final item = snapshot.data!.musicInfoList[index]; + return InkWell( + onTap: () {}, + child: Container( + width: 80.0, + margin: (index == length - 1) + ? EdgeInsets.only(left: 10.0, right: 10.0) + : EdgeInsets.only( + left: 10.0, + ), + decoration: BoxDecoration( + image: DecorationImage( + image: CachedNetworkImageProvider( + item.music.coverLarge), + fit: BoxFit.cover, + ), + borderRadius: BorderRadius.circular(10.0), + ), + ), + ); + }, + ), + ); + } catch (e) { + return Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + color: Colors.black, + child: Center( + child: Text( + 'Error, Please restart your app again.', + style: TextStyle(color: Colors.white), + )), + ); + } + } else { + // empty data + return loading; + } + } else { + return Text('State: ${snapshot.connectionState}'); + } + }, + ); + } +} diff --git a/lib/Screens/search/search.dart b/lib/Screens/search/search.dart index b197d72..25b18db 100644 --- a/lib/Screens/search/search.dart +++ b/lib/Screens/search/search.dart @@ -4,6 +4,7 @@ import 'package:telsavideo/constants.dart'; import 'package:telsavideo/screens/search/dance_item.dart'; import 'package:telsavideo/screens/search/food_item.dart'; import 'package:telsavideo/screens/search/laugh_item.dart'; +import 'package:telsavideo/screens/search/music_item.dart'; class Search extends StatefulWidget { @override @@ -94,13 +95,13 @@ class _SearchState extends State { ), ), SizedBox(height: 10.0), - getHashtagRow('DanceLikeaPro', '108.8k'), - DanceList(), + getHashtagRow('Music', '181.9k'), + MusicItem(), SizedBox(height: 10.0), - getHashtagRow('LaughOutLoud', '159.8k'), + getHashtagRow('User', '159.8k'), LaughList(), SizedBox(height: 10.0), - getHashtagRow('Food', '231.9k'), + getHashtagRow('Challenge', '231.9k'), FoodList(), SizedBox(height: 80.0), ], diff --git a/lib/Screens/search/user_item.dart b/lib/Screens/search/user_item.dart new file mode 100644 index 0000000..b75bbe4 --- /dev/null +++ b/lib/Screens/search/user_item.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:telsavideo/api/api.dart'; +import 'package:telsavideo/models/dto/discover/discover_user_dto.dart'; +import 'package:telsavideo/models/vo/discover/discover_user_vo.dart'; +import 'package:telsavideo/screens/loading/loading.dart'; + +class UserItem extends StatefulWidget { + @override + State createState() => _UserItemState(); +} + +class _UserItemState extends State { + DiscoverUserDto dto = new DiscoverUserDto(0, 20); + + late Future getDicoverUsers; + + @override + void initState() { + // TODO: implement initState + super.initState(); + getDicoverUsers = Api.getDiscoverUser(dto); + } + + @override + Widget build(BuildContext context) { + // TODO: implement build + double width = MediaQuery.of(context).size.width; + return FutureBuilder( + future: getDicoverUsers, + builder: (context, snapshot) { + print(snapshot.connectionState); + if (snapshot.connectionState == ConnectionState.waiting) { + return loading; + } else if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.hasError) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height - 24, + color: Colors.black, + child: Center( + child: Text( + 'Error, Please restart your app again.', + style: TextStyle(color: Colors.white), + )), + ) + ], + ); + } else if (snapshot.hasData) { + try { + return Container(); + } catch (e) { + return Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + color: Colors.black, + child: Center( + child: Text( + 'Error, Please restart your app again.', + style: TextStyle(color: Colors.white), + )), + ); + } + } else { + // empty data + return loading; + } + } else { + return Text('State: ${snapshot.connectionState}'); + } + }, + ); + } +} diff --git a/lib/api/api.dart b/lib/api/api.dart index 80411b0..1b1bc6e 100644 --- a/lib/api/api.dart +++ b/lib/api/api.dart @@ -3,9 +3,11 @@ import 'dart:core'; import 'package:telsavideo/api/http_manager.dart'; import 'package:telsavideo/constants.dart'; import 'package:telsavideo/http/http_constant.dart'; +import 'package:telsavideo/http/response/result.dart'; import 'package:telsavideo/models/dto/comment/comment_item_digg_dto.dart'; import 'package:telsavideo/models/dto/comment/comment_item_list_dto.dart'; import 'package:telsavideo/models/dto/comment/comment_list_reply_dto.dart'; +import 'package:telsavideo/models/dto/discover/banner_dto.dart'; import 'package:telsavideo/models/dto/message/notification_dto.dart'; import 'package:telsavideo/models/dto/discover/discover_challenge_dto.dart'; import 'package:telsavideo/models/dto/discover/discover_music_dto.dart'; @@ -17,6 +19,7 @@ import 'package:telsavideo/models/dto/signup/signup_dto.dart'; import 'package:telsavideo/models/vo/comment/comment_item_digg_vo.dart'; import 'package:telsavideo/models/vo/comment/comment_item_list_vo.dart'; import 'package:telsavideo/models/vo/comment/comment_list_reply_vo.dart'; +import 'package:telsavideo/models/vo/discover/banner_vo.dart'; import 'package:telsavideo/models/vo/discover/discover_challenage_vo.dart'; import 'package:telsavideo/models/vo/discover/discover_music_vo.dart'; import 'package:telsavideo/models/vo/discover/discover_user_vo.dart'; @@ -114,9 +117,21 @@ class Api { return CommentListReplyVo.fromJson(result); } + ///get banner list + static Future postBannerList(BannerDto? dto) async { + Map param = new HashMap(); + var result = await HttpManager.getInstance().post( + url: Api.api + HttpConstant.discoverChallenge, + cancelTokenTag: 'bannerlist', + data: param); + return BannerVo.toJson(result); + } + /// get discover music static Future getDiscoverMusic(DiscoverMusicDto? dto) async { Map params = new HashMap(); + params["cursor"] = dto?.cursor ?? 0; + params["count"] = dto?.count ?? 20; var result = await HttpManager.getInstance().get( url: Api.api + HttpConstant.discoverMusic, cancelTokenTag: 'discovermusic', @@ -129,6 +144,8 @@ class Api { static Future getDiscoverChanllenge( DiscoverChallengeDto? dto) async { Map params = new HashMap(); + params["cursor"] = dto?.cursor ?? 0; + params["count"] = dto?.count ?? 20; var result = await HttpManager.getInstance().get( url: Api.api + HttpConstant.discoverChallenge, cancelTokenTag: 'discoverchallenge', @@ -140,6 +157,8 @@ class Api { /// get discover users static Future getDiscoverUser(DiscoverUserDto? dto) async { Map params = new HashMap(); + params["cursor"] = dto?.cursor ?? 0; + params["count"] = dto?.count ?? 20; var result = await HttpManager.getInstance().get( url: Api.api + HttpConstant.discoverUser, cancelTokenTag: 'discoveruser', diff --git a/lib/models/dto/discover/banner_dto.dart b/lib/models/dto/discover/banner_dto.dart new file mode 100644 index 0000000..632619e --- /dev/null +++ b/lib/models/dto/discover/banner_dto.dart @@ -0,0 +1,6 @@ +/// banner dto +class BannerDto { + int? cursor; + int? count; + BannerDto({this.cursor, this.count}); +} diff --git a/lib/models/dto/discover/discover_challenge_dto.dart b/lib/models/dto/discover/discover_challenge_dto.dart index 4444550..4a9ae4f 100644 --- a/lib/models/dto/discover/discover_challenge_dto.dart +++ b/lib/models/dto/discover/discover_challenge_dto.dart @@ -1 +1,5 @@ -class DiscoverChallengeDto {} +class DiscoverChallengeDto { + int? cursor; + int? count; + DiscoverChallengeDto([this.cursor, this.count]); +} diff --git a/lib/models/dto/discover/discover_music_dto.dart b/lib/models/dto/discover/discover_music_dto.dart index ae4a06b..495821a 100644 --- a/lib/models/dto/discover/discover_music_dto.dart +++ b/lib/models/dto/discover/discover_music_dto.dart @@ -1 +1,5 @@ -class DiscoverMusicDto {} +class DiscoverMusicDto { + int? cursor; + int? count; + DiscoverMusicDto([this.cursor, this.count]); +} diff --git a/lib/models/dto/discover/discover_user_dto.dart b/lib/models/dto/discover/discover_user_dto.dart index 3ff6cfc..52a9763 100644 --- a/lib/models/dto/discover/discover_user_dto.dart +++ b/lib/models/dto/discover/discover_user_dto.dart @@ -1 +1,5 @@ -class DiscoverUserDto {} +class DiscoverUserDto { + int? cursor; + int? count; + DiscoverUserDto([this.cursor, this.count]); +} diff --git a/lib/models/vo/discover/banner_vo.dart b/lib/models/vo/discover/banner_vo.dart new file mode 100644 index 0000000..09230ca --- /dev/null +++ b/lib/models/vo/discover/banner_vo.dart @@ -0,0 +1,8 @@ +class BannerVo { + String? image; + String? title; + String? url; + + BannerVo({this.image, this.title, this.url}); + factory BannerVo.toJson(Map json) => BannerVo(); +} diff --git a/lib/models/vo/discover/discover_music_vo.dart b/lib/models/vo/discover/discover_music_vo.dart index 4ddbdfb..d5a01b1 100644 --- a/lib/models/vo/discover/discover_music_vo.dart +++ b/lib/models/vo/discover/discover_music_vo.dart @@ -1,6 +1,114 @@ class DiscoverMusicVo { - DiscoverMusicVo(); + DiscoverMusicVo({ + required this.musicInfoList, + }); - factory DiscoverMusicVo.fromJson(Map json) => - DiscoverMusicVo(); + late final List musicInfoList; + + DiscoverMusicVo.fromJson(Map json) { + musicInfoList = List.from(json['musicInfoList']) + .map((e) => MusicInfoList.fromJson(e)) + .toList(); + } + + Map toJson() { + final _data = {}; + _data['musicInfoList'] = musicInfoList.map((e) => e.toJson()).toList(); + return _data; + } +} + +class MusicInfoList { + MusicInfoList({ + required this.music, + required this.stats, + }); + late final Music music; + late final Stats stats; + + MusicInfoList.fromJson(Map json) { + music = Music.fromJson(json['music']); + stats = Stats.fromJson(json['stats']); + } + + Map toJson() { + final _data = {}; + _data['music'] = music.toJson(); + _data['stats'] = stats.toJson(); + return _data; + } +} + +class Music { + Music({ + required this.album, + required this.authorName, + required this.coverLarge, + required this.coverMedium, + this.coverThumb, + required this.duration, + required this.id, + required this.original, + this.playUrl, + required this.title, + }); + late final String album; + late final String authorName; + late final String coverLarge; + late final String coverMedium; + late final String? coverThumb; + late final String duration; + late final String id; + late final String original; + late final String? playUrl; + late final String title; + + Music.fromJson(Map json) { + album = json['album']; + authorName = json['authorName']; + coverLarge = json['coverLarge']; + coverMedium = json['coverMedium']; + coverThumb = null; + duration = json['duration']; + id = json['id']; + original = json['original']; + playUrl = null; + title = json['title']; + } + + Map toJson() { + final _data = {}; + _data['album'] = album; + _data['authorName'] = authorName; + _data['coverLarge'] = coverLarge; + _data['coverMedium'] = coverMedium; + _data['coverThumb'] = coverThumb; + _data['duration'] = duration; + _data['id'] = id; + _data['original'] = original; + _data['playUrl'] = playUrl; + _data['title'] = title; + return _data; + } +} + +class Stats { + Stats({ + this.videoCount, + this.viewCount, + }); + late final Null videoCount; + late final Null viewCount; + + Stats.fromJson(Map json) { + videoCount = null; + viewCount = null; + } + + Map toJson() { + final _data = {}; + _data['videoCount'] = videoCount; + _data['viewCount'] = viewCount; + return _data; + } }