달력 만든이후, 해당날짜 누르게되면 툴팁이 나오는 구성
- 미완성 : 툴팁 맨아래 날짜 클릭시 위로올라감
- 미완성 : 툴팁위치조정
import 'dart:convert';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:linker_manager/widgets/nav_left.dart';
class SchedulerScreen extends StatefulWidget {
const SchedulerScreen({super.key});
@override
State<SchedulerScreen> createState() => _SchedulerScreenState();
}
class _SchedulerScreenState extends State<SchedulerScreen> {
DateTime _selectedDate = DateTime.now(); // 현재 날짜
OverlayEntry? _overlayEntry;
DateTime? _activeDate; // 활성화된 날짜
// 해당 월의 시작 요일과 마지막 날짜 계산
int getDaysInMonth(int year, int month) {
return DateTime(year, month + 1, 0).day;
}
void _goToPreviousMonth() {
setState(() {
_hideTooltip(); // 기존 툴팁 제거
_selectedDate = DateTime(_selectedDate.year, _selectedDate.month - 1, 1);
});
}
void _goToNextMonth() {
setState(() {
_hideTooltip(); // 기존 툴팁 제거
_selectedDate = DateTime(_selectedDate.year, _selectedDate.month + 1, 1);
});
}
void _showTooltip(
BuildContext context, DateTime tappedDate, Offset position) {
_hideTooltip(); // 기존 툴팁 제거
print(position.dy);
String year = tappedDate.year.toString();
String month = tappedDate.month.toString().padLeft(2, '0');
String day = tappedDate.day.toString().padLeft(2, '0');
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
// double tooltipWidth = message.length * 8.0; // 글자 수에 따른 가로 크기 추정
double tooltipWidth = 300;
double tooltipHeight = 400.0; // 툴팁 높이
double cellHeight = 18.0; // 날짜 셀의 높이 (대략적인 값)
double adjustedLeft = position.dx;
double adjustedTop = position.dy + cellHeight; // 날짜 셀 아래로 툴팁 위치 조정
// 오른쪽 화면 바깥으로 나가지 않게 조정
if (position.dx + tooltipWidth > screenWidth) {
adjustedLeft = screenWidth - tooltipWidth - 8.0; // 여백 추가
}
// 왼쪽 화면 바깥으로 나가지 않게 조정
if (position.dx < 8.0) {
adjustedLeft = 8.0; // 여백 추가
}
// 아래쪽 화면 바깥으로 나가지 않게 조정
if (adjustedTop + tooltipHeight > screenHeight) {
adjustedTop = position.dy - tooltipHeight - 8.0; // 위로 올려서 조정
}
// 위쪽 화면 바깥으로 나가지 않게 조정
if (adjustedTop < 8.0) {
adjustedTop = 8.0; // 여백 추가
}
_overlayEntry = OverlayEntry(
builder: (context) => Positioned(
top: adjustedTop,
left: adjustedLeft,
child: Material(
color: Colors.transparent,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
decoration: BoxDecoration(
color: const Color.fromARGB(190, 0, 0, 0),
borderRadius: BorderRadius.circular(8.0),
),
child: Column(
mainAxisSize: MainAxisSize.min, // Column의 최소 크기 사용
crossAxisAlignment: CrossAxisAlignment.start, // 왼쪽 정렬
children: [
Text(
"$year.$month.$day",
style: const TextStyle(color: Colors.white, fontSize: 16.0),
textAlign: TextAlign.center,
),
SizedBox(
width: 100,
height: 10,
child: Divider(
height: 20,
color: Theme.of(context).primaryColor,
thickness: 2.0,
indent: 1, // 왼쪽 여백
endIndent: 1, // 오른쪽 여백
),
),
const Text(
"* 문자 보내기",
style: TextStyle(color: Colors.white70, fontSize: 13.0),
textAlign: TextAlign.left,
),
const Text(
"* 문자 보내기",
style: TextStyle(color: Colors.white70, fontSize: 13.0),
textAlign: TextAlign.left,
),
const Text(
"* 문자 보내기",
style: TextStyle(color: Colors.white70, fontSize: 13.0),
textAlign: TextAlign.left,
),
],
),
),
),
),
);
Overlay.of(context).insert(_overlayEntry!);
}
void _hideTooltip() {
_overlayEntry?.remove();
_overlayEntry = null;
}
void _onDateTap(BuildContext context, int year, int month, int day,
TapDownDetails details) {
DateTime tappedDate = DateTime(year, month, day);
if (_activeDate == tappedDate) {
// 활성화된 날짜를 다시 누른 경우
setState(() {
_activeDate = null; // 활성화 해제
});
_hideTooltip();
} else {
// 새로운 날짜를 선택한 경우
setState(() {
_activeDate = tappedDate; // 새로운 활성 날짜 설정
});
_showTooltip(context, tappedDate, details.globalPosition);
}
}
@override
Widget build(BuildContext context) {
int year = _selectedDate.year;
int month = _selectedDate.month;
int daysInMonth = getDaysInMonth(year, month);
int firstDayWeekday = DateTime(year, month, 1).weekday; // 1: 월요일, 7: 일요일
// 날짜 리스트 생성
List<Widget> dayWidgets = [];
for (int i = 1; i < firstDayWeekday; i++) {
dayWidgets.add(Container()); // 빈칸 추가
}
for (int day = 1; day <= daysInMonth; day++) {
DateTime currentDate = DateTime(year, month, day);
bool isActive = currentDate == _activeDate;
dayWidgets.add(
GestureDetector(
onTapDown: (details) {
_onDateTap(context, year, month, day, details);
},
child: Container(
alignment: Alignment.center,
margin: const EdgeInsets.all(4.0),
decoration: BoxDecoration(
color: isActive
? Theme.of(context).primaryColorDark
: Colors.transparent, // 활성화된 날짜 배경 변경
border: Border.all(color: Theme.of(context).primaryColor),
borderRadius: BorderRadius.circular(4.0),
),
child: Text(
'$day',
style: TextStyle(
color:
isActive ? Colors.white : Theme.of(context).primaryColor),
),
),
),
);
}
return Scaffold(
appBar: AppBar(
elevation: 2,
title: Text(
"Scheduler 😃✨",
style: Theme.of(context).textTheme.headlineMedium,
),
leading: Builder(
builder: (context) => IconButton(
icon: const Icon(Icons.menu),
onPressed: () => Scaffold.of(context).openDrawer(),
),
),
),
drawer: const NavLeft(),
body: Column(
children: [
// Header
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
icon: const Icon(Icons.arrow_back_ios),
color: Theme.of(context).primaryColor,
onPressed: _goToPreviousMonth,
),
Text(
'${_selectedDate.year}-${_selectedDate.month.toString().padLeft(2, '0')}',
style:
const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
IconButton(
icon: const Icon(Icons.arrow_forward_ios),
color: Theme.of(context).primaryColor,
onPressed: _goToNextMonth,
),
],
),
// Weekday labels
const Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text('일', style: TextStyle(color: Colors.red)),
Text('월'),
Text('화'),
Text('수'),
Text('목'),
Text('금'),
Text('토', style: TextStyle(color: Colors.blue)),
],
),
// Calendar grid
Expanded(
child: GridView.count(
crossAxisCount: 7, // 일주일이 7일
children: dayWidgets,
),
),
],
),
);
}
}


