Open name27 opened 1 year ago
import 'package:flutter/material.dart'; import 'pages/main_page.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: MainPage(), ); } }
import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/src/widgets/container.dart'; import 'package:flutter/src/widgets/framework.dart'; import 'package:naver_clone_app/pages/search_page.dart'; import 'mail_page.dart'; class MainPage extends StatefulWidget { const MainPage({super.key}); @override State<MainPage> createState() => _MainPageState(); } var listViewController = ScrollController(); class _MainPageState extends State<MainPage> { ValueNotifier<bool> isCur = ValueNotifier<bool>(true); var res; Future<Map<String, dynamic>> getData() async { var dio = Dio(); res = await dio.get( 'https://sfacassignmentchallenge-default-rtdb.europe-west1.firebasedatabase.app/.json'); if (res.statusCode == 200) { return res.data; } return {}; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: GestureDetector( onTap: () { listViewController.animateTo(0, duration: Duration(milliseconds: 300), curve: Curves.easeIn); }, child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ Text('프로모션'), Padding( padding: const EdgeInsets.all(3.0), child: Icon( Icons.circle, color: Colors.greenAccent[400], size: 9, ), ), Text( '34', style: TextStyle(color: Colors.greenAccent[400]), ) ], ), ), centerTitle: true, foregroundColor: Colors.black, backgroundColor: Colors.transparent, elevation: 0, actions: [ IconButton( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => SearchPage(data: res.data["emails"]))); }, icon: Icon( Icons.search_outlined, size: 30, color: Colors.grey, )), IconButton( onPressed: () { isCur.value = !isCur.value; }, icon: Icon( Icons.access_time, size: 30, color: Colors.grey, )), ], ), drawer: Drawer( child: ListView( padding: EdgeInsets.zero, children: [ UserAccountsDrawerHeader( currentAccountPicture: CircleAvatar( backgroundColor: Colors.white, child: Icon( Icons.person, size: 50, color: Colors.grey, ), ), accountName: Text('Test'), accountEmail: Text('test@naver.com'), onDetailsPressed: () { print('clicked'); }, decoration: BoxDecoration( color: Colors.grey, ), ), ListTile( leading: Icon(Icons.mail), title: Text('전체 메일'), ), ListTile( leading: Icon(Icons.email_outlined), title: Text('받은 메일'), ), ListTile( leading: Icon(Icons.send), title: Text('보낸 메일함'), ), ], ), ), body: Center( child: FutureBuilder( future: getData(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const CupertinoActivityIndicator(); } if (!snapshot.hasData) return const Text("데이터가 없습니다"); Map<String, dynamic> data = snapshot.data as Map<String, dynamic>; List<dynamic> emails = data["emails"]; return Container( decoration: BoxDecoration(color: Colors.grey.shade300), child: MailPage( emails: emails, listViewController: listViewController, isCur: isCur, isWidget: false, )); }, ), ), floatingActionButton: MailPage( isWidget: true, )); } }
import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:intl/intl.dart'; import 'package:naver_clone_app/pages/mailDetail_page.dart'; import 'package:naver_clone_app/widget/deleteMail.dart'; import 'package:naver_clone_app/widget/mailCard.dart'; import 'package:naver_clone_app/model/maildata.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'main_page.dart'; class MailPage extends StatefulWidget { const MailPage( {super.key, this.emails, this.listViewController, this.isCur, required this.isWidget}); final dynamic emails; final dynamic listViewController; final dynamic isCur; final bool isWidget; @override State<MailPage> createState() => _MailPageState(); } var _refreshController = RefreshController(); List<Map<String, dynamic>> deleteMail = []; var i = 0; class _MailPageState extends State<MailPage> { void _onRefresh() async { setState(() {}); await Future.delayed(Duration(milliseconds: 500)); _refreshController.refreshCompleted(); } @override Widget build(BuildContext context) { if (!widget.isWidget) { return ValueListenableBuilder( valueListenable: widget.isCur, builder: (context, value, child) { var emails = widget.emails; if (!widget.isCur.value) { emails = List.from(widget.emails.reversed); } return SmartRefresher( enablePullUp: false, header: WaterDropHeader( waterDropColor: Colors.transparent, idleIcon: Icon( Icons.refresh_outlined, size: 35, )), controller: _refreshController, onRefresh: _onRefresh, child: ListView.builder( controller: listViewController, itemBuilder: (context, index) { Mail emaildata = Mail.fromMap(emails[index]); var sendDateTime = DateTime.parse(emaildata.sendDate.replaceAll('.', '-')); if (sendDateTime.year == DateTime.now().year) { emaildata.sendDate = DateFormat('MM.dd').format(sendDateTime); if (sendDateTime.month == DateTime.now().month) { var day = DateTime.now().day - sendDateTime.day; switch (day) { case 0: emaildata.sendDate = "오늘"; break; case 1: emaildata.sendDate = "어제"; break; } } } else if (sendDateTime.year != DateTime.now().year) { emaildata.sendDate = DateFormat('yyyy.MM.dd').format(sendDateTime); } return Dismissible( direction: DismissDirection.endToStart, background: Container( color: Colors.red, child: Center( child: Icon( Icons.delete_outline, size: 40, )), ), key: UniqueKey(), onDismissed: (direction) { if (emails[index] != null) { deleteMail.add({}); deleteMail[i].addAll(emails[index]); i++; } setState(() { emails.removeAt(index); }); }, child: GestureDetector( onTap: (){ Navigator.push(context, MaterialPageRoute(builder: (context) => MailDetailPage(data: emails[index]),)); }, child: MailCard( emaildata: emaildata, ), )); }, itemCount: emails.length), ); }, ); } else { return DeleteMail(deleteMail: deleteMail); } } }
import 'package:flutter/material.dart'; import 'package:flutter/src/widgets/container.dart'; import 'package:flutter/src/widgets/framework.dart'; class MailDetailPage extends StatelessWidget { const MailDetailPage({super.key, required this.data}); final Map<String, dynamic> data; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.white, foregroundColor: Colors.black, elevation: 0.5, actions: [ IconButton( onPressed: () {}, icon: Icon( Icons.mail_outline_outlined, size: 30, )), IconButton( onPressed: () {}, icon: Icon( Icons.delete_forever, size: 30, )), IconButton( onPressed: () {}, icon: Icon( Icons.more_vert, size: 30, )) ], ), body: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(left:8.0, top: 8, right: 8), child: Row( children: [ Text('보낸 사람'), Padding( padding: const EdgeInsets.symmetric(horizontal:3.0), child: Icon( Icons.arrow_drop_down_circle, color: Colors.grey, size: 15, ), ), Padding( padding: const EdgeInsets.symmetric(horizontal:5.0), child: Text(data["from"]), ) ], ), ), Divider( thickness: 1, ), Padding( padding: const EdgeInsets.symmetric(horizontal:8.0), child: Text( data["title"], style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), ), ), Padding( padding: const EdgeInsets.symmetric(horizontal:8.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(data["sendDate"]), Icon( Icons.star, color: Colors.grey, ) ], ), ), Divider( thickness: 1, ), Padding( padding: const EdgeInsets.all(12.0), child: Container( width: 400, child: RichText( overflow: TextOverflow.clip, strutStyle: StrutStyle(fontSize: 16.0), text: TextSpan( text: data["detail"], style: TextStyle( fontSize: 15, color: Colors.black, fontWeight: FontWeight.w500)), ), ), ), ], ), ); } }
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/src/widgets/framework.dart'; import 'package:naver_clone_app/model/maildata.dart'; import 'package:naver_clone_app/pages/mailDetail_page.dart'; import 'package:naver_clone_app/widget/mailCard.dart'; class SearchPage extends StatefulWidget { const SearchPage({super.key, required this.data}); final List<dynamic> data; @override State<SearchPage> createState() => _SearchPageState(); } var _inputController = TextEditingController(); List<String> searchList = []; bool _isSearch = false; bool _isCorrect = false; var _searchIndex; class _SearchPageState extends State<SearchPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.transparent, foregroundColor: Colors.black, elevation: 0, title: TextField( onSubmitted: (value) { _isSearch = !_isSearch; searchList.insert(0, value); for (int i = 0; i < widget.data.length; i++) { if (widget.data[i]["from"] == value) { _isCorrect = true; _searchIndex = i; } } setState(() {}); print(searchList); }, controller: _inputController, decoration: InputDecoration( hintText: '메일 검색', enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: Colors.transparent, width: 0.3, ), ), ), ), actions: [ IconButton( onPressed: () { _inputController.text = ""; _isCorrect = false; setState(() {}); }, icon: Icon(Icons.close)) ], ), body: _isSearch && _isCorrect ? InkWell( onTap: () { _isCorrect = false; Navigator.push( context, MaterialPageRoute( builder: (context) => MailDetailPage(data: widget.data[_searchIndex]), )); }, child: MailCard( emaildata: Mail.fromMap(widget.data[_searchIndex]), ), ) : ListView.separated( itemCount: searchList.length, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.only( left: 12.0, right: 12, bottom: 5, top: 5), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ TextButton( onPressed: () { _inputController.text = searchList[index]; }, child: Text( searchList[index], style: TextStyle(color: Colors.black), ), ), TextButton( onPressed: () { for (int i = 0; i < widget.data.length; i++) { if (widget.data[i]["from"] == searchList[index]) { Navigator.push( context, MaterialPageRoute( builder: (context) => MailDetailPage( data: widget.data[i], ), )); } } }, child: Text( ' (전체) ', style: TextStyle(color: Colors.grey), ), ), ], ), IconButton( onPressed: () { searchList.removeAt(index); setState(() {}); }, icon: Icon( Icons.close, color: Colors.grey, )) ], ), ], ), ); }, separatorBuilder: (context, index) => Divider( thickness: 2, ), ), ); } }
import 'package:flutter/material.dart'; import 'package:flutter/src/widgets/framework.dart'; import 'package:intl/intl.dart'; import '../model/maildata.dart'; import 'mailCard.dart'; class DeleteMail extends StatelessWidget { const DeleteMail({super.key, required this.deleteMail}); final List deleteMail; @override Widget build(BuildContext context) { return FloatingActionButton( onPressed: () { showModalBottomSheet<void>( context: context, builder: (BuildContext context) { return ListView.builder( itemBuilder: (context, index) { Mail emaildata = Mail.fromMap(deleteMail[index]); var sendDateTime = DateTime.parse(emaildata.sendDate.replaceAll('.', '-')); if (sendDateTime.year == DateTime.now().year) { emaildata.sendDate = DateFormat('MM.dd').format(sendDateTime); if (sendDateTime.month == DateTime.now().month) { var day = DateTime.now().day - sendDateTime.day; switch (day) { case 0: emaildata.sendDate = "오늘"; break; case 1: emaildata.sendDate = "어제"; break; } } } else if (sendDateTime.year != DateTime.now().year) { emaildata.sendDate = DateFormat('yyyy.MM.dd').format(sendDateTime); } return MailCard( emaildata: emaildata, ); }, itemCount: deleteMail.length); ; }, ); }, backgroundColor: Colors.greenAccent[400], child: Icon( Icons.delete_outline_outlined, size: 35, ), ); } }
import 'package:flutter/material.dart'; import 'package:flutter/src/widgets/container.dart'; import 'package:flutter/src/widgets/framework.dart'; import 'package:flutter/widgets.dart'; import 'package:naver_clone_app/model/maildata.dart'; class MailCard extends StatelessWidget { const MailCard({super.key, required this.emaildata}); final Mail emaildata; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 3.0), child: AspectRatio( aspectRatio: 7 / 2, child: Card( child: Padding( padding: const EdgeInsets.all(3.0), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Padding( padding: const EdgeInsets.all(8.0), child: Icon( Icons.circle, size: 8, color: Colors.greenAccent[400], ), ), Text(emaildata.title, style: TextStyle( fontWeight: FontWeight.w600, fontSize: 16)), ], ), Row( mainAxisSize: MainAxisSize.min, children: [ Text(emaildata.sendDate), Icon( Icons.star, color: Colors.grey.shade300, ) ], ) ], ), Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Row( children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 4.0), child: Container( padding: EdgeInsets.symmetric(horizontal: 5.5), decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.circular(13)), child: Text( 'To', style: TextStyle(color: Colors.white), )), ), Container( width: 300, child: RichText( overflow: TextOverflow.clip, maxLines: 1, strutStyle: StrutStyle(fontSize: 16.0), text: TextSpan( text: emaildata.from, style: TextStyle( fontSize: 15, color: Colors.black, fontWeight: FontWeight.w500)), ), ), ], ), ), ], ), Padding( padding: const EdgeInsets.only(left: 8, right: 8, bottom: 8), child: Container( width: 350, child: RichText( overflow: TextOverflow.clip, maxLines: 2, strutStyle: StrutStyle(fontSize: 16.0), text: TextSpan( text: emaildata.detail, style: TextStyle(fontSize: 15, color: Colors.black)), ), ), ), ], ), ), ), ), ); } Widget _buildMailCard() { return Padding( padding: const EdgeInsets.symmetric(horizontal: 3.0), child: AspectRatio( aspectRatio: 7 / 2, child: Card( child: Padding( padding: const EdgeInsets.all(3.0), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Padding( padding: const EdgeInsets.all(8.0), child: Icon( Icons.circle, size: 8, color: Colors.greenAccent[400], ), ), Text(emaildata.title, style: TextStyle( fontWeight: FontWeight.w600, fontSize: 16)), ], ), Row( mainAxisSize: MainAxisSize.min, children: [ Text(emaildata.sendDate), Icon( Icons.star, color: Colors.grey.shade300, ) ], ) ], ), Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Row( children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 4.0), child: Container( padding: EdgeInsets.symmetric(horizontal: 5.5), decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.circular(13)), child: Text( 'To', style: TextStyle(color: Colors.white), )), ), Container( width: 300, child: RichText( overflow: TextOverflow.clip, maxLines: 1, strutStyle: StrutStyle(fontSize: 16.0), text: TextSpan( text: emaildata.from, style: TextStyle( fontSize: 15, color: Colors.black, fontWeight: FontWeight.w500)), ), ), ], ), ), ], ), Padding( padding: const EdgeInsets.only(left: 8, right: 8, bottom: 8), child: Container( width: 350, child: RichText( overflow: TextOverflow.clip, maxLines: 2, strutStyle: StrutStyle(fontSize: 16.0), text: TextSpan( text: emaildata.detail, style: TextStyle(fontSize: 15, color: Colors.black)), ), ), ), ], ), ), ), ), ); } }
main.dart
main_page.dart
mail_page.dart
mailDetail_page.dart
search_page.dart
deleteMail.dart
mailCard.dart