design + logic updates
parent
9b5b09045b
commit
79380eb2e0
|
@ -1,11 +1,13 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:moody/utils/SlideDirection.dart';
|
||||
import 'package:moody/views/color_page/color_page.dart';
|
||||
import 'package:moody/views/entry_view/entry_page.dart';
|
||||
import 'package:moody/views/first_page/first_page.dart';
|
||||
import 'package:moody/views/home_page/home_page.dart';
|
||||
import 'package:moody/views/home_page/kalendartryhome_page.dart';
|
||||
import 'package:moody/views/settings_page/settings_page.dart';
|
||||
import 'package:moody/views/start_page/start_page.dart';
|
||||
import 'package:moody/views/statistic/statistic_page.dart';
|
||||
import 'package:moody/views/write_page/write_page.dart';
|
||||
|
||||
|
@ -16,7 +18,7 @@ final GoRouter _router = GoRouter(
|
|||
GoRoute(
|
||||
path: '/',
|
||||
pageBuilder: (context, state) =>
|
||||
_noAnimationTransition(context, state, FirstPage()),
|
||||
_noAnimationTransition(context, state, StartPage()),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/moods',
|
||||
|
@ -34,9 +36,19 @@ final GoRouter _router = GoRouter(
|
|||
),
|
||||
GoRoute(
|
||||
path: '/home',
|
||||
pageBuilder: (context, state) =>
|
||||
_noAnimationTransition(context, state, HomePage()),
|
||||
),
|
||||
pageBuilder: (context, state) =>
|
||||
_noAnimationTransition(context, state, HomePage()),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/first',
|
||||
pageBuilder: (context, state) =>
|
||||
_noAnimationTransition(context, state, FirstPage()),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/color',
|
||||
pageBuilder: (context, state) =>
|
||||
_noAnimationTransition(context, state, ColorPage()),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/write',
|
||||
builder: (context, state) {
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import 'dart:math' as Math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CirclePainter extends CustomPainter {
|
||||
final double value;
|
||||
final Color color; // New field for color
|
||||
|
||||
CirclePainter(this.value);
|
||||
CirclePainter(this.value, this.color);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
var paint = Paint()
|
||||
..color = Colors.greenAccent.withOpacity(0.5)
|
||||
..color = color.withOpacity(0.5) // Use the passed color
|
||||
..style = PaintingStyle.fill;
|
||||
|
||||
double radius = value * 500 / 100;
|
||||
print(radius);
|
||||
|
||||
double radius = Math.pow(((value + 5) * 500 / 100) / 1.5, 1.14).toDouble();
|
||||
canvas.drawCircle(Offset(size.width / 6, size.height / 4), radius, paint);
|
||||
//print(size.width / 6);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class ColorPair {
|
||||
final Color textColor;
|
||||
final Color backgroundColor;
|
||||
final String name;
|
||||
|
||||
ColorPair(
|
||||
{required this.name,
|
||||
required this.textColor,
|
||||
required this.backgroundColor});
|
||||
}
|
||||
|
||||
List<ColorPair> colorPairs = [
|
||||
ColorPair(
|
||||
name: "origin",
|
||||
textColor: Color(0xff446F2F),
|
||||
backgroundColor: Color(0xffC9E7BB)),
|
||||
ColorPair(
|
||||
name: "lavender",
|
||||
textColor: Color(0xff765EAB),
|
||||
backgroundColor: Color(0xffD3CAE7)),
|
||||
ColorPair(
|
||||
name: "orange",
|
||||
textColor: Color(0xffC78233),
|
||||
backgroundColor: Color(0xffF0CFA9)),
|
||||
ColorPair(
|
||||
name: "rose",
|
||||
textColor: Color(0xffB15555),
|
||||
backgroundColor: Color(0xffEBD6D6)),
|
||||
ColorPair(
|
||||
name: "mountain",
|
||||
textColor: Color(0xff1D6289),
|
||||
backgroundColor: Color(0xffB4D0E0)),
|
||||
ColorPair(
|
||||
name: "moon",
|
||||
textColor: Color(0xff7A83C7),
|
||||
backgroundColor: Color(0xff393C55)),
|
||||
ColorPair(
|
||||
name: "forest",
|
||||
textColor: Color(0xffC9E7BB),
|
||||
backgroundColor: Color(0xff4C5847)),
|
||||
// ...add other color pairs with names...
|
||||
];
|
|
@ -3,28 +3,37 @@ import 'dart:ui';
|
|||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../definitions/ColorPairs.dart';
|
||||
|
||||
class PreferencesService {
|
||||
static const _keyColor1 = 'color1';
|
||||
static const _keyColor2 = 'color2';
|
||||
static const _keyDiaryEntries = 'diaryEntries';
|
||||
static const _keyPin = 'userPin';
|
||||
static const _keyPinEnabled = 'pinEnabled';
|
||||
|
||||
// Load color preferences
|
||||
Future<ColorPreference> loadColors() async {
|
||||
// Helper method to save a ColorPair preference
|
||||
Future<void> saveColorPair(ColorPair colorPair) async {
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(
|
||||
_keyColor1, colorPair.backgroundColor.value.toString());
|
||||
await prefs.setString(_keyColor2, colorPair.textColor.value.toString());
|
||||
}
|
||||
|
||||
// Helper method to load the ColorPair preference
|
||||
Future<ColorPair> loadColorPair() async {
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
final String? color1 = prefs.getString(_keyColor1);
|
||||
final String? color2 = prefs.getString(_keyColor2);
|
||||
|
||||
return ColorPreference(
|
||||
color1: color1 != null ? Color(int.parse(color1)) : null,
|
||||
color2: color2 != null ? Color(int.parse(color2)) : null,
|
||||
);
|
||||
}
|
||||
|
||||
// Save color preferences
|
||||
Future<void> saveColors(Color color1, Color color2) async {
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_keyColor1, color1.value.toString());
|
||||
await prefs.setString(_keyColor2, color2.value.toString());
|
||||
if (color1 != null && color2 != null) {
|
||||
return ColorPair(
|
||||
name: "Custom", // You might want to handle naming differently
|
||||
textColor: Color(int.parse(color2)),
|
||||
backgroundColor: Color(int.parse(color1)),
|
||||
);
|
||||
}
|
||||
return colorPairs[0]; // Return null if no color pair is set
|
||||
}
|
||||
|
||||
// Get the diary entry for the current date
|
||||
|
@ -113,6 +122,42 @@ class PreferencesService {
|
|||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
// Set PIN method
|
||||
Future<void> setPin(int pin) async {
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setInt(_keyPin, pin);
|
||||
await prefs.setBool(
|
||||
_keyPinEnabled, true); // Automatically enable PIN on setting
|
||||
}
|
||||
|
||||
// Check PIN method
|
||||
Future<bool> checkPin(int pin) async {
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
int savedPin = prefs.getInt(_keyPin) ?? -1; // Default to -1 if not set
|
||||
return savedPin == pin;
|
||||
}
|
||||
|
||||
// Check if PIN is enabled
|
||||
Future<bool> isPinEnabled() async {
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getBool(_keyPinEnabled) ?? false; // Return false if not set
|
||||
}
|
||||
|
||||
// Enable PIN
|
||||
Future<void> enablePin() async {
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
if (prefs.getInt(_keyPin) != null) {
|
||||
// Ensure PIN exists before enabling
|
||||
await prefs.setBool(_keyPinEnabled, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Disable PIN
|
||||
Future<void> disablePin() async {
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool(_keyPinEnabled, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper class to store color preferences
|
||||
|
|
|
@ -5,11 +5,11 @@ class QuestionGenerator {
|
|||
"Welche Begebenheit hat heute dein Herz am meisten erfreut?",
|
||||
"Was war das Highlight deines Tages, das dir ein Lächeln geschenkt hat?",
|
||||
"Welche besondere Erfahrung heute hat dir neue Energie und Freude gebracht?",
|
||||
"gut?",
|
||||
"Wie gehts?",
|
||||
"What's up?",
|
||||
"How arr you",
|
||||
"You ok?",
|
||||
"how fullfilled do you feel today?",
|
||||
"how fullfilled do you feel today?",
|
||||
"how fullfilled do you feel today?",
|
||||
"how fullfilled do you feel today?",
|
||||
"how fullfilled do you feel today?",
|
||||
];
|
||||
|
||||
String getQuestionByDate(DateTime date) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:moody/utils/definitions/ColorPairs.dart';
|
||||
import 'package:moody/utils/logic/PreferencesService.dart';
|
||||
|
||||
class CustomBottomNavigationBar extends StatefulWidget {
|
||||
final int initialSelectedIndex;
|
||||
|
@ -47,6 +49,28 @@ class _CustomBottomNavigationBarState extends State<CustomBottomNavigationBar> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder<ColorPair>(
|
||||
future:
|
||||
PreferencesService().loadColorPair(), // Async loading of the color
|
||||
builder: (BuildContext context, AsyncSnapshot<ColorPair> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
// When data is loaded
|
||||
Color backgroundColor =
|
||||
snapshot.data!.backgroundColor; // Use loaded background color
|
||||
return buildNavigationBar(backgroundColor);
|
||||
} else {
|
||||
// While loading or if no data, show default or loading indicator
|
||||
return buildNavigationBar(
|
||||
Colors.white); // Default color or loading indicator
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildNavigationBar(Color backgroundColor) {
|
||||
Future<ColorPair> globalColors = PreferencesService().loadColorPair();
|
||||
return Container(
|
||||
width: 175,
|
||||
margin: EdgeInsets.only(left: 130, right: 130, bottom: 30),
|
||||
|
@ -77,22 +101,25 @@ class _CustomBottomNavigationBarState extends State<CustomBottomNavigationBar> {
|
|||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
_buildNavItem(Image.asset('assets/icons/icon-analyze.png'), 0),
|
||||
_buildNavItem(Image.asset('assets/icons/icon-logo.png'), 1),
|
||||
_buildNavItem(Image.asset('assets/icons/icon-settings.png'), 2),
|
||||
_buildNavItem(Image.asset('assets/icons/icon-analyze.png'), 0,
|
||||
backgroundColor),
|
||||
_buildNavItem(
|
||||
Image.asset('assets/icons/icon-logo.png'), 1, backgroundColor),
|
||||
_buildNavItem(Image.asset('assets/icons/icon-settings.png'), 2,
|
||||
backgroundColor),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildNavItem(Image icon, int index) {
|
||||
Widget _buildNavItem(Image icon, int index, Color selectedColor) {
|
||||
return Container(
|
||||
height: 40,
|
||||
width:40,
|
||||
width: 40,
|
||||
decoration: _selectedIndex == index
|
||||
? BoxDecoration(
|
||||
color: Colors.lightGreen,
|
||||
color: selectedColor,
|
||||
borderRadius: BorderRadius.circular(40),
|
||||
)
|
||||
: null,
|
||||
|
|
|
@ -2,14 +2,13 @@ import 'package:flutter/material.dart';
|
|||
import 'package:intl/intl.dart';
|
||||
import 'package:moody/utils/logic/QuestionGenerator.dart';
|
||||
|
||||
import '../CirclePainter.dart';
|
||||
|
||||
class QuestionSliderWidget extends StatefulWidget {
|
||||
final DateTime date;
|
||||
final String questionText;
|
||||
final double initialSliderValue;
|
||||
final bool isSliderEnabled;
|
||||
final ValueChanged<double> onSliderChanged;
|
||||
final ValueChanged<SliderChangeData> onSliderChanged;
|
||||
final ValueChanged<double> onSliderPositionChanged;
|
||||
|
||||
QuestionSliderWidget({
|
||||
Key? key,
|
||||
|
@ -18,6 +17,7 @@ class QuestionSliderWidget extends StatefulWidget {
|
|||
required this.initialSliderValue,
|
||||
required this.isSliderEnabled,
|
||||
required this.onSliderChanged,
|
||||
required this.onSliderPositionChanged,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
|
@ -25,34 +25,30 @@ class QuestionSliderWidget extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _QuestionSliderWidgetState extends State<QuestionSliderWidget> {
|
||||
late double _sliderValue;
|
||||
bool _sliderChanged = false;
|
||||
bool _showDragText = true;
|
||||
SliderChangeData _sliderData = SliderChangeData(0, 0);
|
||||
QuestionGenerator generator = QuestionGenerator();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_sliderValue = widget.initialSliderValue;
|
||||
_sliderData.value = widget.initialSliderValue;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
top: 20,
|
||||
left: _calculateSliderPosition(context, _sliderValue) - 60,
|
||||
child: CustomPaint(
|
||||
painter: CirclePainter(_sliderValue),
|
||||
),
|
||||
),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 150, 20, 0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
// Date
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 150, 20, 20),
|
||||
padding: const EdgeInsets.fromLTRB(30, 0, 0, 30),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
// Date
|
||||
children: [
|
||||
Text(
|
||||
DateFormat('dd MM yyyy').format(widget.date),
|
||||
style: TextStyle(fontSize: 18),
|
||||
|
@ -62,10 +58,17 @@ class _QuestionSliderWidgetState extends State<QuestionSliderWidget> {
|
|||
generator.getQuestionByDate(widget.date),
|
||||
style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
|
||||
),
|
||||
// Slider and label
|
||||
SliderTheme(
|
||||
],
|
||||
),
|
||||
),
|
||||
// Slider and label
|
||||
Stack(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(15, 0, 0, 15),
|
||||
child: SliderTheme(
|
||||
data: SliderTheme.of(context).copyWith(
|
||||
disabledThumbColor: Colors.amber,
|
||||
disabledThumbColor: Colors.transparent,
|
||||
activeTrackColor: Colors.black,
|
||||
trackShape: RectangularSliderTrackShape(),
|
||||
inactiveTickMarkColor: Colors.red,
|
||||
|
@ -77,7 +80,7 @@ class _QuestionSliderWidgetState extends State<QuestionSliderWidget> {
|
|||
trackHeight: 2,
|
||||
thumbColor: Colors.transparent,
|
||||
thumbShape: RoundSliderThumbShape(
|
||||
enabledThumbRadius: 30.0,
|
||||
enabledThumbRadius: 10.0,
|
||||
elevation: 0,
|
||||
disabledThumbRadius: 0),
|
||||
rangeThumbShape: RoundRangeSliderThumbShape(
|
||||
|
@ -86,35 +89,40 @@ class _QuestionSliderWidgetState extends State<QuestionSliderWidget> {
|
|||
elevation: 0,
|
||||
),
|
||||
),
|
||||
child: Stack(
|
||||
alignment: Alignment.centerLeft,
|
||||
children: [
|
||||
Slider(
|
||||
min: 0.0,
|
||||
max: 100.0,
|
||||
value: _sliderValue,
|
||||
onChanged: widget.isSliderEnabled
|
||||
? (value) {
|
||||
setState(() {
|
||||
_sliderValue = value;
|
||||
_sliderChanged = true;
|
||||
});
|
||||
widget.onSliderChanged(value);
|
||||
}
|
||||
: null,
|
||||
),
|
||||
Positioned(
|
||||
left: _calculateSliderPosition(context, _sliderValue),
|
||||
child: Text(
|
||||
"${_sliderValue.toStringAsFixed(0)}%",
|
||||
style: TextStyle(fontSize: 20), // Size increased by 2
|
||||
),
|
||||
),
|
||||
],
|
||||
child: Slider(
|
||||
min: 0.0,
|
||||
max: 100.0,
|
||||
value: _sliderData.value,
|
||||
onChanged: widget.isSliderEnabled
|
||||
? (value) {
|
||||
setState(() {
|
||||
_sliderData.position =
|
||||
_calculateSliderPosition(context, value);
|
||||
_sliderData.value = value;
|
||||
_showDragText = false;
|
||||
});
|
||||
widget.onSliderChanged(SliderChangeData(
|
||||
_sliderData.value, _sliderData.position));
|
||||
}
|
||||
: null,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: _calculateSliderPosition(context, _sliderData.value),
|
||||
child: IgnorePointer(
|
||||
child: _showDragText
|
||||
? Text(
|
||||
"Drag Me -->",
|
||||
style: TextStyle(fontSize: 16),
|
||||
)
|
||||
: Text(
|
||||
"${_sliderData.value.toStringAsFixed(0)}%",
|
||||
style: TextStyle(fontSize: 20),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -128,3 +136,10 @@ class _QuestionSliderWidgetState extends State<QuestionSliderWidget> {
|
|||
return (sliderWidth - thumbWidth) * value / 100.0 + thumbWidth / 2;
|
||||
}
|
||||
}
|
||||
|
||||
class SliderChangeData {
|
||||
double value;
|
||||
double position; // Additional data you might want to include
|
||||
|
||||
SliderChangeData(this.value, this.position);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../utils/definitions/ColorPairs.dart';
|
||||
import '../../utils/logic/PreferencesService.dart';
|
||||
import '../../utils/widgets/BottomNavigationWidget.dart';
|
||||
|
||||
// ...Include PreferencesService and other necessary imports
|
||||
|
||||
class ColorPage extends StatefulWidget {
|
||||
@override
|
||||
_ColorPageState createState() => _ColorPageState();
|
||||
}
|
||||
|
||||
class _ColorPageState extends State<ColorPage> {
|
||||
int? selectedColorIndex; // Index of the selected color
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadSelectedColor();
|
||||
}
|
||||
|
||||
// Load selected color from preferences
|
||||
void _loadSelectedColor() async {
|
||||
ColorPair? savedColorPair = await PreferencesService().loadColorPair();
|
||||
if (savedColorPair != null) {
|
||||
// Find the index of the saved color in the colorPairs list
|
||||
int index = colorPairs.indexWhere(
|
||||
(pair) =>
|
||||
pair.backgroundColor.value ==
|
||||
savedColorPair.backgroundColor.value &&
|
||||
pair.textColor.value == savedColorPair.textColor.value,
|
||||
);
|
||||
if (index != -1) {
|
||||
setState(() {
|
||||
selectedColorIndex = index;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// If no color is selected, default to the first one
|
||||
setState(() {
|
||||
selectedColorIndex = 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(30, 150, 30, 30),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 50),
|
||||
child: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
Icon(Icons.chevron_left, color: Colors.black), // "<" icon
|
||||
Text("settings",
|
||||
style: TextStyle(color: Colors.black, fontSize: 18)),
|
||||
]),
|
||||
),
|
||||
Text("change color", style: TextStyle(fontSize: 24)),
|
||||
SizedBox(height: 30),
|
||||
Wrap(
|
||||
spacing: 15, // space between circles horizontally
|
||||
runSpacing: 15, // space between circles vertically
|
||||
children: List.generate(
|
||||
colorPairs.length, (index) => buildColorCircle(index)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 50.0),
|
||||
child: Text("Can't find your favorite color?",
|
||||
style: TextStyle(color: Colors.grey)),
|
||||
),
|
||||
Text("Wish you a color!", style: TextStyle(color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
|
||||
floatingActionButton: CustomBottomNavigationBar(initialSelectedIndex: 2),
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function to build a single color circle
|
||||
Widget buildColorCircle(int index) {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
selectedColorIndex = index; // Set selected color
|
||||
});
|
||||
await PreferencesService().saveColorPair(colorPairs[index]);
|
||||
},
|
||||
child: Container(
|
||||
width: 120,
|
||||
height: 120,
|
||||
padding: EdgeInsets.all(10), // Padding for inner circle effect
|
||||
decoration: BoxDecoration(
|
||||
color: colorPairs[index].backgroundColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: selectedColorIndex == index
|
||||
? Border.all(color: Colors.black, width: 1)
|
||||
: null,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
colorPairs[index].name,
|
||||
style:
|
||||
TextStyle(color: colorPairs[index].textColor, fontSize: 16),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:moody/utils/widgets/QuestionSliderWidget.dart';
|
||||
|
||||
import '../../utils/CirclePainter.dart';
|
||||
import '../../utils/definitions/ColorPairs.dart';
|
||||
import '../../utils/logic/PreferencesService.dart';
|
||||
|
||||
class FirstPage extends StatefulWidget {
|
||||
|
@ -10,10 +12,28 @@ class FirstPage extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _FirstPageState extends State<FirstPage> {
|
||||
SliderChangeData sliderData = SliderChangeData(0, 0);
|
||||
double _sliderValue = 0.0;
|
||||
bool _sliderChanged = false;
|
||||
PreferencesService _prefsService = PreferencesService();
|
||||
|
||||
Color backgroundColor = Colors.lightGreenAccent;
|
||||
Color textColor = Colors.black;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadColor();
|
||||
}
|
||||
|
||||
void _loadColor() async {
|
||||
ColorPair colorPair = await PreferencesService().loadColorPair();
|
||||
setState(() {
|
||||
backgroundColor = colorPair.backgroundColor;
|
||||
textColor = colorPair.textColor;
|
||||
});
|
||||
}
|
||||
|
||||
void _saveEntry() async {
|
||||
try {
|
||||
List<String> texts = [];
|
||||
|
@ -32,64 +52,77 @@ class _FirstPageState extends State<FirstPage> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
body: SafeArea(
|
||||
child: Stack(
|
||||
children: [
|
||||
// Background circle
|
||||
/*Positioned.fill(
|
||||
child: CustomPaint(
|
||||
painter: CirclePainter(_sliderValue),
|
||||
),
|
||||
),*/
|
||||
// Main content
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
// Date
|
||||
QuestionSliderWidget(
|
||||
date: DateTime.now(),
|
||||
questionText: "How are you today",
|
||||
initialSliderValue: 0,
|
||||
isSliderEnabled: true,
|
||||
onSliderChanged: (value) {
|
||||
setState(() {
|
||||
_sliderValue = value;
|
||||
});
|
||||
}),
|
||||
// Why? button
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.go('/write', extra: _sliderValue);
|
||||
|
||||
// Implement your why? functionality here
|
||||
},
|
||||
child: Text("Why?"),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Skip/Save button
|
||||
Positioned(
|
||||
bottom: 20,
|
||||
right: 20,
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
print(_sliderChanged);
|
||||
if (_sliderChanged) {
|
||||
_saveEntry();
|
||||
context.go('/home', extra: _sliderValue);
|
||||
} else {
|
||||
context.go('/home', extra: 0);
|
||||
}
|
||||
},
|
||||
child: Text(_sliderChanged ? "Save" : "Skip"),
|
||||
return backgroundColor == Colors.lightGreenAccent
|
||||
? CircularProgressIndicator() // Show loading indicator while color is null
|
||||
: MaterialApp(
|
||||
home: Scaffold(
|
||||
body: SafeArea(
|
||||
child: Stack(
|
||||
children: [
|
||||
// Background circle
|
||||
Positioned.fill(
|
||||
top: 15,
|
||||
left: sliderData.position - 70,
|
||||
child: CustomPaint(
|
||||
painter:
|
||||
CirclePainter(sliderData.value, backgroundColor),
|
||||
),
|
||||
),
|
||||
// Main content
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
// Date
|
||||
Stack(
|
||||
children: [
|
||||
QuestionSliderWidget(
|
||||
onSliderPositionChanged: (value) {
|
||||
print("sliderposchanged");
|
||||
},
|
||||
date: DateTime.now(),
|
||||
questionText: "",
|
||||
initialSliderValue: 0,
|
||||
isSliderEnabled: true,
|
||||
onSliderChanged: (value) {
|
||||
setState(() {
|
||||
sliderData = value;
|
||||
if (!_sliderChanged) _sliderChanged = true;
|
||||
});
|
||||
}),
|
||||
],
|
||||
),
|
||||
// Why? button
|
||||
_sliderChanged
|
||||
? TextButton(
|
||||
onPressed: () {
|
||||
context.go('/write', extra: sliderData.value);
|
||||
},
|
||||
child: Text("warum?"),
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
],
|
||||
),
|
||||
// Skip/Save button
|
||||
Positioned(
|
||||
bottom: 20,
|
||||
right: 20,
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
print(_sliderChanged);
|
||||
if (_sliderChanged) {
|
||||
_saveEntry();
|
||||
context.go('/home', extra: sliderData.value);
|
||||
} else {
|
||||
context.go('/home', extra: 0);
|
||||
}
|
||||
},
|
||||
child: Text(_sliderChanged ? "Save" : "Skip"),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ class _DragWidgetState extends State<DragWidget> {
|
|||
children: [
|
||||
Positioned.fill(
|
||||
child: CustomPaint(
|
||||
painter: CirclePainter(_sliderValue),
|
||||
painter: CirclePainter(_sliderValue, Colors.red),
|
||||
),
|
||||
),
|
||||
Column(
|
||||
|
|
|
@ -68,20 +68,23 @@ class _HomePageState extends State<HomePage> {
|
|||
// Background circle
|
||||
Positioned.fill(
|
||||
child: CustomPaint(
|
||||
painter: CirclePainter(_sliderValue),
|
||||
painter: CirclePainter(_sliderValue, Colors.orange),
|
||||
),
|
||||
),
|
||||
SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
QuestionSliderWidget(
|
||||
onSliderPositionChanged: (value) {
|
||||
print("sliderposchanged");
|
||||
},
|
||||
date: DateTime.now(),
|
||||
questionText: 'this is how it is:',
|
||||
initialSliderValue: _sliderValue,
|
||||
isSliderEnabled: true,
|
||||
onSliderChanged: (value) {
|
||||
setState(() {
|
||||
_sliderValue = value;
|
||||
_sliderValue = value.value;
|
||||
});
|
||||
},
|
||||
),
|
||||
|
|
|
@ -1,102 +1,124 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../utils/widgets/BottomNavigationWidget.dart';
|
||||
import 'widgets/CustomDivider.dart';
|
||||
import 'widgets/SetPinPopup.dart';
|
||||
import 'widgets/TextSwitchContainer.dart';
|
||||
|
||||
class SettingsPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ListView(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 16.0),
|
||||
backgroundColor: Color(0xffeeeeee),
|
||||
body: Container(
|
||||
padding: EdgeInsets.only(bottom: 0),
|
||||
margin: const EdgeInsets.fromLTRB(30, 30, 30, 0),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
const SizedBox(
|
||||
height: 100,
|
||||
),
|
||||
|
||||
// Settings section
|
||||
Container(
|
||||
margin: EdgeInsets.only(bottom: 10),
|
||||
alignment: Alignment.topLeft,
|
||||
child: Text('settings',
|
||||
style:
|
||||
TextStyle(fontWeight: FontWeight.w500, fontSize: 24)),
|
||||
),
|
||||
TextSwitchContainer(
|
||||
leftText: "change color",
|
||||
onTap: () => context.go("/color"),
|
||||
),
|
||||
CustomDivider(),
|
||||
TextSwitchContainer(
|
||||
leftText: "pin",
|
||||
hasSwitch: true,
|
||||
onTap: () => {showSetPinPopup(context)},
|
||||
onSwitchToggle: (value) => print('Switch toggled: $value'),
|
||||
),
|
||||
CustomDivider(),
|
||||
TextSwitchContainer(
|
||||
leftText: "your data",
|
||||
onTap: () => print('Container tapped'),
|
||||
),
|
||||
// Community section
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 50, 0, 10),
|
||||
child: Container(
|
||||
alignment: Alignment.topLeft,
|
||||
margin: EdgeInsets.only(bottom: 10),
|
||||
child: Text('community',
|
||||
style:
|
||||
TextStyle(fontWeight: FontWeight.w500, fontSize: 24)),
|
||||
),
|
||||
),
|
||||
TextSwitchContainer(
|
||||
leftText: "join our discord",
|
||||
rightText: "fullfilled",
|
||||
onTap: () => print('Container tapped'),
|
||||
),
|
||||
CustomDivider(),
|
||||
TextSwitchContainer(
|
||||
leftText: "our instagram",
|
||||
rightText: "@get.fullfilled",
|
||||
onTap: () => print('Container tapped'),
|
||||
),
|
||||
CustomDivider(),
|
||||
TextSwitchContainer(
|
||||
leftText: "share fullfilled with your loved ones",
|
||||
onTap: () => print('Container tapped'),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 50, 0, 10),
|
||||
child: Container(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Text('humans behind fullfilled',
|
||||
style:
|
||||
TextStyle(fontWeight: FontWeight.w500, fontSize: 24)),
|
||||
),
|
||||
),
|
||||
TextSwitchContainer(
|
||||
leftText: "about us",
|
||||
onTap: () => print('Container tapped'),
|
||||
),
|
||||
CustomDivider(),
|
||||
TextSwitchContainer(
|
||||
leftText: "support us",
|
||||
onTap: () => print('Container tapped'),
|
||||
),
|
||||
CustomDivider(),
|
||||
TextSwitchContainer(
|
||||
leftText: "give feedback",
|
||||
onTap: () => print('Container tapped'),
|
||||
),
|
||||
//
|
||||
ListTile(
|
||||
title: Text('imprint & privacy policy',
|
||||
style: TextStyle(color: Colors.grey, fontSize: 15)),
|
||||
onTap: () => {}, // Implement your logic
|
||||
),
|
||||
SizedBox(
|
||||
height: 150,
|
||||
)
|
||||
],
|
||||
),
|
||||
// Settings section
|
||||
ListTile(
|
||||
title:
|
||||
Text('settings', style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
),
|
||||
ListTile(
|
||||
title: Text('change color'),
|
||||
onTap: () => {}, // Implement your logic
|
||||
),
|
||||
Divider(),
|
||||
// Community section
|
||||
ListTile(
|
||||
title: Text('notifications'),
|
||||
onTap: () => {}, // Implement your logic
|
||||
),
|
||||
Divider(),
|
||||
// Community section
|
||||
ListTile(
|
||||
title: Text('set pin'),
|
||||
onTap: () => {}, // Implement your logic
|
||||
),
|
||||
Divider(),
|
||||
// Community section
|
||||
ListTile(
|
||||
title: Text('export your data'),
|
||||
onTap: () => {}, // Implement your logic
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 16.0),
|
||||
),
|
||||
ListTile(
|
||||
title: Text('community',
|
||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
),
|
||||
ListTile(
|
||||
title: Text('join our discord'),
|
||||
trailing: Text('fulfilled'),
|
||||
onTap: () => {}, // Implement your logic
|
||||
),
|
||||
Divider(),
|
||||
//
|
||||
ListTile(
|
||||
title: Text('our instagram'),
|
||||
trailing: Text('@get_fulfilled'),
|
||||
onTap: () => {}, // Implement your logic
|
||||
),
|
||||
Divider(),
|
||||
//
|
||||
ListTile(
|
||||
title: Text('share fulfilled with your loved ones'),
|
||||
onTap: () => {}, // Implement your logic
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 16.0),
|
||||
),
|
||||
ListTile(
|
||||
title: Text('humans behind fulfilled',
|
||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
),
|
||||
ListTile(
|
||||
title: Text('about us'),
|
||||
onTap: () => {}, // Implement your logic
|
||||
),
|
||||
Divider(),
|
||||
//
|
||||
ListTile(
|
||||
title: Text('support us'),
|
||||
onTap: () => {}, // Implement your logic
|
||||
),
|
||||
Divider(),
|
||||
//
|
||||
ListTile(
|
||||
title: Text('give feedback'),
|
||||
onTap: () => {}, // Implement your logic
|
||||
),
|
||||
Divider(),
|
||||
//
|
||||
ListTile(
|
||||
title: Text('imprint & privacy policy',
|
||||
style: TextStyle(color: Colors.grey)),
|
||||
onTap: () => {}, // Implement your logic
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
|
||||
floatingActionButton: CustomBottomNavigationBar(initialSelectedIndex: 3),
|
||||
floatingActionButton: CustomBottomNavigationBar(initialSelectedIndex: 2),
|
||||
);
|
||||
}
|
||||
|
||||
void showSetPinPopup(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return SetPinPopup();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class CustomDivider extends StatelessWidget {
|
||||
const CustomDivider({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Divider(
|
||||
color: Colors.grey.shade300,
|
||||
thickness: 1, // Set thickness to 1px
|
||||
height: 1, // Set height to 1px to reduce padding
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../../../utils/logic/PreferencesService.dart'; // For HapticFeedback
|
||||
|
||||
// ...Include PreferencesService and other necessary imports
|
||||
|
||||
class SetPinPopup extends StatefulWidget {
|
||||
@override
|
||||
_SetPinPopupState createState() => _SetPinPopupState();
|
||||
}
|
||||
|
||||
class _SetPinPopupState extends State<SetPinPopup> {
|
||||
String _pin = '';
|
||||
String _confirmedPin = '';
|
||||
bool _isSettingPin =
|
||||
true; // True if setting the PIN, false if confirming the PIN
|
||||
|
||||
static const int pinLength = 4;
|
||||
|
||||
// Include the methods from PinInputScreen here
|
||||
List<Widget> _buildNumberPad() {
|
||||
List<int> numbers = List.generate(9, (index) => index + 1);
|
||||
List<Widget> rows = [];
|
||||
|
||||
// First three rows (1-9)
|
||||
for (var i = 0; i < 3; i++) {
|
||||
rows.add(
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: numbers.skip(i * 3).take(3).map((number) {
|
||||
return _buildNumberButton(number);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Last row with 0
|
||||
rows.add(
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(width: 70), // Empty container to align 0 in center
|
||||
_buildNumberButton(0),
|
||||
Container(width: 70), // Empty container to align 0 in center
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
Widget _buildNumberButton(int number) {
|
||||
return GestureDetector(
|
||||
onTap: () => _onNumberTap(number),
|
||||
onTapDown: (_) =>
|
||||
HapticFeedback.lightImpact(), // Cool haptic feedback on tap
|
||||
child: Container(
|
||||
width: 70,
|
||||
height: 70,
|
||||
margin: EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
border: Border.all(color: Colors.black),
|
||||
borderRadius: BorderRadius.circular(35),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
number.toString(),
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onNumberTap(int number) {
|
||||
setState(() {
|
||||
if (_isSettingPin) {
|
||||
_pin += number.toString();
|
||||
} else {
|
||||
_confirmedPin += number.toString();
|
||||
}
|
||||
});
|
||||
|
||||
if ((_isSettingPin && _pin.length == pinLength) ||
|
||||
(!_isSettingPin && _confirmedPin.length == pinLength)) {
|
||||
if (!_isSettingPin && _pin == _confirmedPin) {
|
||||
// Call setPin and enablePin methods, assuming they are async
|
||||
PreferencesService().setPin(int.parse(_pin));
|
||||
PreferencesService().enablePin();
|
||||
Navigator.of(context).pop(); // Close the dialog
|
||||
} else if (!_isSettingPin && _pin != _confirmedPin) {
|
||||
// PINs don't match, reset and let the user set the PIN again
|
||||
setState(() {
|
||||
_pin = '';
|
||||
_confirmedPin = '';
|
||||
_isSettingPin = true; // Reset back to setting PIN
|
||||
});
|
||||
} else {
|
||||
// Move to confirming the PIN
|
||||
setState(() {
|
||||
_isSettingPin = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
backgroundColor: Colors.transparent,
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
|
||||
child: Container(
|
||||
height: 600,
|
||||
width: 400,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.all(Radius.circular(50))),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(_isSettingPin ? 'Set a PIN' : 'Repeat PIN',
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: List.generate(pinLength, (index) {
|
||||
return Container(
|
||||
margin: EdgeInsets.all(4),
|
||||
width: 15,
|
||||
height: 15,
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
(_isSettingPin ? _pin.length : _confirmedPin.length) >
|
||||
index
|
||||
? Colors.black
|
||||
: Colors.transparent,
|
||||
border: Border.all(color: Colors.grey),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
..._buildNumberPad(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TextSwitchContainer extends StatefulWidget {
|
||||
final String leftText;
|
||||
final String? rightText;
|
||||
final bool hasSwitch;
|
||||
final Function onTap;
|
||||
final Function(bool)? onSwitchToggle;
|
||||
|
||||
TextSwitchContainer({
|
||||
required this.leftText,
|
||||
this.rightText,
|
||||
this.hasSwitch = false,
|
||||
required this.onTap,
|
||||
this.onSwitchToggle,
|
||||
});
|
||||
|
||||
@override
|
||||
_TextSwitchContainerState createState() => _TextSwitchContainerState();
|
||||
}
|
||||
|
||||
class _TextSwitchContainerState extends State<TextSwitchContainer> {
|
||||
bool switchValue = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => widget.onTap(),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 0, vertical: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
widget.leftText,
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
if (widget.hasSwitch)
|
||||
CupertinoSwitch(
|
||||
trackColor: Colors.white,
|
||||
thumbColor: switchValue ? Colors.lightGreen : Colors.grey,
|
||||
value: switchValue,
|
||||
onChanged: (newValue) {
|
||||
setState(() {
|
||||
switchValue = newValue;
|
||||
widget.onSwitchToggle?.call(newValue);
|
||||
});
|
||||
},
|
||||
activeColor: Colors.white, // Active (ON) color
|
||||
// CupertinoSwitch doesn't allow inactive thumb color customization by default
|
||||
// Track color changes with the active color
|
||||
)
|
||||
else if (widget.rightText != null)
|
||||
Text(
|
||||
widget.rightText!,
|
||||
style: TextStyle(fontSize: 16, color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../utils/logic/PreferencesService.dart'; // For Haptic Feedback
|
||||
|
||||
class StartPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'PIN Input',
|
||||
home: PinInputScreen(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PinInputScreen extends StatefulWidget {
|
||||
@override
|
||||
_PinInputScreenState createState() => _PinInputScreenState();
|
||||
}
|
||||
|
||||
class _PinInputScreenState extends State<PinInputScreen> {
|
||||
String _pin = '';
|
||||
static const int pinLength = 4;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_checkPinStatus();
|
||||
}
|
||||
|
||||
Future<void> _checkPinStatus() async {
|
||||
bool pinEnabled = await PreferencesService()
|
||||
.isPinEnabled(); // Adjust with actual implementation
|
||||
if (!pinEnabled) {
|
||||
// If no PIN is enabled, navigate to the "/first" route.
|
||||
// Navigator context will be available after the widget build.
|
||||
Future.microtask(() => context.go("/first"));
|
||||
}
|
||||
}
|
||||
|
||||
// This method would be your actual method for checking the pin
|
||||
// Replace with your actual method from PreferencesService
|
||||
Future<bool> checkPin(int pin) async {
|
||||
bool pinRight = await PreferencesService().checkPin(pin);
|
||||
return pinRight;
|
||||
}
|
||||
|
||||
void _onNumberTap(int number) {
|
||||
if (_pin.length < pinLength) {
|
||||
setState(() {
|
||||
_pin += number.toString();
|
||||
});
|
||||
|
||||
if (_pin.length == pinLength) {
|
||||
_validatePin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _validatePin() async {
|
||||
bool correct = await checkPin(int.parse(_pin));
|
||||
if (correct) {
|
||||
print("Right");
|
||||
context.go("/first");
|
||||
// Perform any actions you need on successful pin entry
|
||||
} else {
|
||||
// Handle wrong pin entry, e.g., reset pin, show error, etc.
|
||||
print("Wrong PIN");
|
||||
}
|
||||
|
||||
// Resetting the PIN for this example, you might want to do this differently
|
||||
setState(() {
|
||||
_pin = '';
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.grey.shade200, // Light gray background
|
||||
body: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.grey, Colors.red.shade100],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: Container(
|
||||
height: 600,
|
||||
width: 400,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.all(Radius.circular(50))),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text('Welcome Back!',
|
||||
style:
|
||||
TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: List.generate(pinLength, (index) {
|
||||
return Container(
|
||||
margin: EdgeInsets.all(4),
|
||||
width: 15,
|
||||
height: 15,
|
||||
decoration: BoxDecoration(
|
||||
color: _pin.length > index
|
||||
? Colors.black
|
||||
: Colors.transparent,
|
||||
border: Border.all(color: Colors.grey),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
..._buildNumberPad(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildNumberPad() {
|
||||
List<int> numbers = List.generate(9, (index) => index + 1);
|
||||
List<Widget> rows = [];
|
||||
|
||||
// First three rows (1-9)
|
||||
for (var i = 0; i < 3; i++) {
|
||||
rows.add(
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: numbers.skip(i * 3).take(3).map((number) {
|
||||
return _buildNumberButton(number);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Last row with 0
|
||||
rows.add(
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(width: 70), // Empty container to align 0 in center
|
||||
_buildNumberButton(0),
|
||||
Container(width: 70), // Empty container to align 0 in center
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
Widget _buildNumberButton(int number) {
|
||||
return GestureDetector(
|
||||
onTap: () => _onNumberTap(number),
|
||||
onTapDown: (_) =>
|
||||
HapticFeedback.lightImpact(), // Cool haptic feedback on tap
|
||||
child: Container(
|
||||
width: 70,
|
||||
height: 70,
|
||||
margin: EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.black),
|
||||
borderRadius: BorderRadius.circular(35),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
number.toString(),
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -21,25 +21,24 @@ class StatisticPage extends StatelessWidget {
|
|||
"browse your memories!",
|
||||
style: TextStyle(fontSize: 24),
|
||||
),
|
||||
Container(
|
||||
height: 650,
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
child: CalendarWidget(currentDate: DateTime.now())),
|
||||
Container(
|
||||
child: CalendarWidget(
|
||||
currentDate: DateTime(
|
||||
DateTime.now().year,
|
||||
DateTime.now().month - 1,
|
||||
DateTime.now().day))),
|
||||
Container(
|
||||
child: CalendarWidget(
|
||||
currentDate: DateTime(
|
||||
DateTime.now().year,
|
||||
DateTime.now().month - 2,
|
||||
DateTime.now().day))),
|
||||
DateTime.now().day - 3))),
|
||||
Container(
|
||||
child: CalendarWidget(
|
||||
currentDate: DateTime(
|
||||
DateTime.now().year,
|
||||
DateTime.now().month - 1,
|
||||
DateTime.now().day - 1))),
|
||||
Container(
|
||||
child: CalendarWidget(currentDate: DateTime.now())),
|
||||
SizedBox(
|
||||
height: 50,
|
||||
)
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../../../utils/definitions/ColorPairs.dart';
|
||||
import '../../../utils/logic/PreferencesService.dart'; // Correct the path as necessary
|
||||
|
||||
class CalendarWidget extends StatefulWidget {
|
||||
final DateTime currentDate;
|
||||
|
||||
|
@ -14,12 +15,32 @@ class CalendarWidget extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _CalendarWidgetState extends State<CalendarWidget> {
|
||||
late List<DateTime> dateList;
|
||||
List<DateTime> dateList = []; // Initialized immediately as an empty list
|
||||
Map<String, DiaryEntry?> diaryEntries = {}; // Holds diary entries by date
|
||||
late ColorPair currentColorPair; // Holds the current color pair
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
dateList = _generateDateList(widget.currentDate);
|
||||
dateList = _generateDateList(widget.currentDate); // Ensured initialization
|
||||
_loadColorPairAndDiaryData();
|
||||
}
|
||||
|
||||
void _loadColorPairAndDiaryData() async {
|
||||
// Load color pair
|
||||
currentColorPair =
|
||||
await PreferencesService().loadColorPair() ?? colorPairs[0];
|
||||
|
||||
// Generate date list
|
||||
//dateList = _generateDateList(widget.currentDate);
|
||||
|
||||
// Load diary entries for each date
|
||||
for (DateTime date in dateList) {
|
||||
DiaryEntry? entry = await PreferencesService().getDiaryEntryByDate(date);
|
||||
String key = DateFormat('yyyy-MM-dd').format(date);
|
||||
diaryEntries[key] = entry;
|
||||
}
|
||||
setState(() {}); // Update the state to reflect new data
|
||||
}
|
||||
|
||||
List<DateTime> _generateDateList(DateTime date) {
|
||||
|
@ -52,64 +73,126 @@ class _CalendarWidgetState extends State<CalendarWidget> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
print(dateList.length);
|
||||
double addon = dateList.length > 35 ? 50 : 0;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: Colors.black.withOpacity(0.3),
|
||||
style: BorderStyle.solid,
|
||||
width: 2))),
|
||||
height: 300 + addon,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(25, 0, 25, 0),
|
||||
child: GridView.builder(
|
||||
physics:
|
||||
NeverScrollableScrollPhysics(), // Disable scrolling for GridView
|
||||
String monthName =
|
||||
DateFormat("MMMM yyyy").format(widget.currentDate); // For month header
|
||||
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 7,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
DateTime date = dateList[index];
|
||||
bool isCurrentMonth = date.month == widget.currentDate.month;
|
||||
double outerRadius = 25; // Fixed outer radius
|
||||
double innerRadius = Random().nextDouble() * outerRadius;
|
||||
double opacity = isCurrentMonth ? 1.0 : 0.15;
|
||||
return FutureBuilder<ColorPair>(
|
||||
future: PreferencesService().loadColorPair(),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return Center(child: CircularProgressIndicator());
|
||||
}
|
||||
ColorPair colorPair = snapshot.data!;
|
||||
|
||||
return Center(
|
||||
child: GestureDetector(
|
||||
onTap: () => {
|
||||
context.go('/entry', extra: date)
|
||||
}, // Using the callback here
|
||||
child: Container(
|
||||
width: outerRadius * 2,
|
||||
height: outerRadius * 2,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: Colors.black, width: 2),
|
||||
color: isCurrentMonth
|
||||
? Colors.transparent
|
||||
: Colors.grey.withOpacity(opacity),
|
||||
),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
CircleWidget(
|
||||
radius: innerRadius,
|
||||
color: Colors.lightGreenAccent.withOpacity(0.75)),
|
||||
Text(
|
||||
DateFormat("d").format(date),
|
||||
style: TextStyle(color: Colors.black),
|
||||
return Container(
|
||||
height: 360 + addon,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Text(monthName,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold)), // Month Header
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(25, 0, 25, 0),
|
||||
child: GridView.builder(
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 7,
|
||||
),
|
||||
],
|
||||
itemBuilder: (context, index) {
|
||||
DateTime date = dateList[index];
|
||||
bool isCurrentMonth =
|
||||
date.month == widget.currentDate.month;
|
||||
double opacity = isCurrentMonth ? 1.0 : 0.15;
|
||||
|
||||
// Fetching diary entry percentage value
|
||||
DiaryEntry? entry =
|
||||
diaryEntries[DateFormat('yyyy-MM-dd').format(date)];
|
||||
double fillPercentage =
|
||||
entry != null ? entry.percentValue / 100.0 : 0.0;
|
||||
|
||||
return Center(
|
||||
child: GestureDetector(
|
||||
onTap: () => {context.go('/entry', extra: date)},
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border:
|
||||
Border.all(color: Colors.black, width: 2),
|
||||
color: DateTime.now().day == date.day &&
|
||||
DateTime.now().month == date.month &&
|
||||
DateTime.now().year == date.year
|
||||
? Colors
|
||||
.orange // Setting background color for current day
|
||||
: isCurrentMonth
|
||||
? Colors.transparent
|
||||
: Colors.grey.withOpacity(opacity),
|
||||
),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
CircleWidget(
|
||||
radius: 25 * fillPercentage,
|
||||
color: fillPercentage > 0
|
||||
? colorPair.backgroundColor
|
||||
: Colors.teal.withOpacity(opacity)),
|
||||
Text(
|
||||
DateFormat("d").format(date),
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
itemCount: dateList.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
itemCount: dateList.length,
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildDateCell(DateTime date, DiaryEntry? entry) {
|
||||
bool isCurrentMonth = date.month == widget.currentDate.month;
|
||||
double opacity = isCurrentMonth ? 1.0 : 0.5;
|
||||
Color bgColor = entry != null
|
||||
? currentColorPair.backgroundColor.withOpacity(opacity)
|
||||
: Colors.transparent;
|
||||
double fillPercentage = entry != null
|
||||
? entry.percentValue / 100
|
||||
: 0; // Assuming percentValue is 0-100
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
context.go('/entry', extra: date);
|
||||
},
|
||||
child: Container(
|
||||
// ... existing decoration adjusted for opacity ...
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
// Inner circle representing diary entry value
|
||||
CircleWidget(
|
||||
radius: 25 * fillPercentage, // Adjust radius based on value
|
||||
color: fillPercentage > 0
|
||||
? currentColorPair.backgroundColor
|
||||
: Colors.grey.withOpacity(opacity)),
|
||||
Text(
|
||||
DateFormat("d").format(date),
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -58,7 +58,7 @@ class _WritePageState extends State<WritePage> {
|
|||
// Background circle
|
||||
Positioned.fill(
|
||||
child: CustomPaint(
|
||||
painter: CirclePainter(_sliderValue),
|
||||
painter: CirclePainter(_sliderValue, Colors.yellowAccent),
|
||||
),
|
||||
),
|
||||
// Main content
|
||||
|
@ -70,13 +70,16 @@ class _WritePageState extends State<WritePage> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
QuestionSliderWidget(
|
||||
onSliderPositionChanged: (value) {
|
||||
print("sliderposchanged");
|
||||
},
|
||||
date: DateTime.now(),
|
||||
questionText: "How are you today",
|
||||
initialSliderValue: 0,
|
||||
isSliderEnabled: true,
|
||||
onSliderChanged: (value) {
|
||||
setState(() {
|
||||
_sliderValue = value;
|
||||
// _sliderValue = value;
|
||||
});
|
||||
}),
|
||||
TextButton(
|
||||
|
|
Loading…
Reference in New Issue