Skip to content

Commit 46e1745

Browse files
committed
refactor through util.dart
1 parent 799fbce commit 46e1745

File tree

8 files changed

+293
-288
lines changed

8 files changed

+293
-288
lines changed

myapp/lib/component/search.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import 'package:google_fonts/google_fonts.dart';
44
import 'package:provider/provider.dart';
55

66
import '../content/bookinfo.dart';
7-
import '../content/bookmark.dart';
87
import 'util.dart';
98

109
class BookSearchContent extends StatefulWidget {

myapp/lib/component/util.dart

Lines changed: 252 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,215 @@
11
import 'package:flutter/material.dart';
2+
import '../component/graphql_client.dart';
3+
import 'package:google_fonts/google_fonts.dart';
4+
5+
/// Theme color definitions
6+
class AppColors {
7+
static const Color primaryGreen = Color(0xFFABF4D0);
8+
static const Color darkGreen = Color(0xFF037549);
9+
static const Color lightGreen = ColoAr(0xFF28DF99);
10+
static const Color primaryBrown = Color(0xFF3E2723);
11+
static const Color lightBrown = Color(0xFFD0C38F);
12+
static const Color lightCream = Color(0xFFF8E6C8);
13+
static const Color lightYellow = Color(0xFFFFDBAD);
14+
}
15+
16+
/// Layout spacing and sizing
17+
class AppDimensions {
18+
static const double defaultPadding = 24.0;
19+
static const double smallSpacing = 8.0;
20+
static const double mediumSpacing = 16.0;
21+
static const double largeSpacing = 40.0;
22+
static const double buttonHeight = 50.0;
23+
static const double borderRadius = 8.0;
24+
static const double bookLogoWidth = 225.0;
25+
static const double bookLogoHeight = 284.0;
26+
}
27+
28+
/// Typography styles
29+
class AppStyles {
30+
static TextStyle get titleStyle => GoogleFonts.nanumPenScript(
31+
fontSize: 40,
32+
color: Colors.black,
33+
);
34+
35+
static TextStyle get headerStyle => const TextStyle(
36+
fontSize: 24,
37+
fontWeight: FontWeight.bold,
38+
);
39+
40+
static TextStyle get subHeaderStyle => const TextStyle(
41+
fontSize: 20,
42+
fontWeight: FontWeight.bold,
43+
);
44+
45+
static TextStyle get bodyStyle => const TextStyle(
46+
fontSize: 18,
47+
);
48+
49+
static TextStyle get labelStyle => const TextStyle(
50+
fontSize: 16,
51+
fontWeight: FontWeight.bold,
52+
);
53+
54+
static TextStyle get captionStyle => const TextStyle(
55+
fontSize: 12,
56+
color: Colors.black54,
57+
);
58+
}
59+
60+
// -------------------------------
61+
// Common Reusable Widgets
62+
// -------------------------------
63+
class CommonWidgets {
64+
/// Book Logo with title overlay
65+
static Widget buildBookLogo() {
66+
return Stack(
67+
alignment: Alignment.center,
68+
children: [
69+
Image.asset(
70+
'assets/images/book.png',
71+
fit: BoxFit.contain,
72+
width: AppDimensions.bookLogoWidth,
73+
height: AppDimensions.bookLogoHeight,
74+
),
75+
Positioned(
76+
child: Text(
77+
'오늘의 책',
78+
style: AppStyles.titleStyle,
79+
textAlign: TextAlign.center,
80+
),
81+
),
82+
],
83+
);
84+
}
85+
86+
/// Custom text input field
87+
static Widget buildInputField({
88+
required String label,
89+
required TextEditingController controller,
90+
String? hintText,
91+
bool isPassword = false,
92+
bool enabled = true,
93+
}) {
94+
return Column(
95+
crossAxisAlignment: CrossAxisAlignment.start,
96+
children: [
97+
Text(label, style: AppStyles.labelStyle),
98+
const SizedBox(height: AppDimensions.smallSpacing),
99+
Container(
100+
decoration: BoxDecoration(
101+
color: AppColors.lightBrown,
102+
borderRadius: BorderRadius.circular(AppDimensions.borderRadius),
103+
),
104+
child: TextField(
105+
controller: controller,
106+
obscureText: isPassword,
107+
enabled: enabled,
108+
decoration: InputDecoration(
109+
hintText: hintText,
110+
contentPadding: const EdgeInsets.symmetric(
111+
horizontal: AppDimensions.mediumSpacing,
112+
vertical: 12,
113+
),
114+
border: InputBorder.none,
115+
),
116+
),
117+
),
118+
],
119+
);
120+
}
121+
122+
static Widget buildPrimaryButton({
123+
required String text,
124+
required VoidCallback? onPressed,
125+
Color backgroundColor = AppColors.primaryBrown,
126+
Color foregroundColor = Colors.white,
127+
bool isLoading = false,
128+
double? width,
129+
}) {
130+
return ElevatedButton(
131+
onPressed: onPressed,
132+
style: ElevatedButton.styleFrom(
133+
backgroundColor: backgroundColor,
134+
foregroundColor: foregroundColor,
135+
minimumSize: Size(width ?? double.infinity, AppDimensions.buttonHeight),
136+
shape: RoundedRectangleBorder(
137+
borderRadius: BorderRadius.circular(AppDimensions.borderRadius),
138+
),
139+
),
140+
child: isLoading
141+
? const SizedBox(
142+
height: 20,
143+
width: 20,
144+
child: CircularProgressIndicator(
145+
strokeWidth: 2,
146+
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
147+
),
148+
)
149+
: Text(text),
150+
);
151+
}
152+
153+
static Widget buildSecondaryButton({
154+
required String text,
155+
required VoidCallback? onPressed,
156+
double? width,
157+
}) {
158+
return ElevatedButton(
159+
onPressed: onPressed,
160+
style: ElevatedButton.styleFrom(
161+
backgroundColor: AppColors.lightBrown,
162+
foregroundColor: Colors.black,
163+
minimumSize: Size(width ?? double.infinity, AppDimensions.buttonHeight),
164+
shape: RoundedRectangleBorder(
165+
borderRadius: BorderRadius.circular(AppDimensions.borderRadius),
166+
),
167+
),
168+
child: Text(text),
169+
);
170+
}
171+
172+
static Widget buildNextButton({
173+
required VoidCallback onPressed,
174+
}) {
175+
return Align(
176+
alignment: Alignment.centerRight,
177+
child: ElevatedButton(
178+
onPressed: onPressed,
179+
style: ElevatedButton.styleFrom(
180+
backgroundColor: AppColors.lightCream,
181+
foregroundColor: Colors.black,
182+
minimumSize: const Size(100, 45),
183+
shape: RoundedRectangleBorder(
184+
borderRadius: BorderRadius.circular(AppDimensions.borderRadius),
185+
),
186+
),
187+
child: const Text("다음"),
188+
),
189+
);
190+
}
191+
192+
static AppBar buildAppBar({VoidCallback? onBackPressed}) {
193+
return AppBar(
194+
backgroundColor: Colors.transparent,
195+
elevation: 0,
196+
leading: IconButton(
197+
icon: const Icon(Icons.arrow_back, color: Colors.black),
198+
onPressed: onBackPressed,
199+
),
200+
);
201+
}
202+
203+
static void showSnackBar(BuildContext context, String message,
204+
{bool isError = false}) {
205+
ScaffoldMessenger.of(context).showSnackBar(
206+
SnackBar(
207+
content: Text(message),
208+
backgroundColor: isError ? Colors.red : Colors.green,
209+
),
210+
);
211+
}
212+
}
2213

3214
Widget buildBookCover(String? coverUrl, double x, double y) {
4215
return ClipRRect(
@@ -15,4 +226,44 @@ Widget buildBookCover(String? coverUrl, double x, double y) {
15226
)
16227
: const Icon(Icons.book, size: 100),
17228
);
18-
}
229+
}
230+
231+
class BookmarksProvider extends ChangeNotifier {
232+
final List<String> _bookmarkedBooks = [];
233+
final List<String> _excludedBookmarked = [];
234+
235+
List<String> get bookmarkedBooks => _bookmarkedBooks;
236+
237+
Future<void> addBookmark(String bookId) async {
238+
_bookmarkedBooks.add(bookId);
239+
await _updateShelf();
240+
notifyListeners();
241+
}
242+
243+
Future<void> removeBookmark(String bookId) async {
244+
_bookmarkedBooks.remove(bookId);
245+
_excludedBookmarked.add(bookId);
246+
await _updateShelf();
247+
notifyListeners();
248+
}
249+
250+
Future<void> _updateShelf() async {
251+
try {
252+
debugPrint(_bookmarkedBooks.toString());
253+
debugPrint(_excludedBookmarked.toString());
254+
final shelfResult = await GraphQLService.updateShelf(
255+
'default', _bookmarkedBooks, _excludedBookmarked);
256+
if (shelfResult != null) {
257+
debugPrint('Default shelf updated successfully');
258+
} else {
259+
debugPrint('Failed to update default shelf');
260+
}
261+
} catch (e) {
262+
debugPrint('Error update default shelf: $e');
263+
}
264+
}
265+
266+
bool isBookmarked(String bookId) {
267+
return _bookmarkedBooks.contains(bookId);
268+
}
269+
}
Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import 'package:flutter/material.dart';
22
import 'package:google_fonts/google_fonts.dart';
3-
import 'package:graphql_flutter/graphql_flutter.dart';
43
import '../component/graphql_client.dart';
54
import '../component/util.dart';
65

@@ -53,9 +52,9 @@ class _BookRecommendationContentState extends State<BookRecommendationContent>
5352
return DefaultTabController(
5453
length: 2,
5554
child: Scaffold(
56-
backgroundColor: const Color(0xFFB7FFE3),
55+
backgroundColor: AppColors.primaryGreen,
5756
appBar: AppBar(
58-
backgroundColor: const Color(0xFFB7FFE3),
57+
backgroundColor: AppColors.primaryGreen,
5958
elevation: 0,
6059
centerTitle: true,
6160
title: Text(
@@ -107,7 +106,7 @@ class _BookRecommendationContentState extends State<BookRecommendationContent>
107106
selectedKeyword = isSelected ? '' : keyword;
108107
});
109108
},
110-
selectedColor: const Color(0xFF5D3A00),
109+
selectedColor: AppColors.primaryBrown,
111110
backgroundColor: Colors.white,
112111
labelStyle: TextStyle(
113112
color: isSelected ? Colors.white : Colors.black,
@@ -122,7 +121,7 @@ class _BookRecommendationContentState extends State<BookRecommendationContent>
122121
? null
123122
: () => fetchRecommendations(selectedKeyword),
124123
style: ElevatedButton.styleFrom(
125-
backgroundColor: const Color(0xFF5D3A00),
124+
backgroundColor: AppColors.primaryBrown,
126125
padding:
127126
const EdgeInsets.symmetric(horizontal: 50, vertical: 16),
128127
),
@@ -164,7 +163,7 @@ class _BookRecommendationContentState extends State<BookRecommendationContent>
164163
? null
165164
: () => fetchRecommendations(_searchController.text.trim()),
166165
style: ElevatedButton.styleFrom(
167-
backgroundColor: const Color(0xFF5D3A00),
166+
backgroundColor: AppColors.primaryBrown,
168167
padding:
169168
const EdgeInsets.symmetric(horizontal: 50, vertical: 16),
170169
),
@@ -185,8 +184,6 @@ class _BookRecommendationContentState extends State<BookRecommendationContent>
185184
isLoading = true;
186185
});
187186

188-
final ValueNotifier<GraphQLClient> client = GraphQLService.getClient();
189-
190187
try {
191188
final books = await GraphQLService.recommendBooks(keyword, 5);
192189
setState(() {
@@ -216,14 +213,9 @@ class RecommendationResultScreen extends StatelessWidget {
216213
@override
217214
Widget build(BuildContext context) {
218215
return Scaffold(
219-
backgroundColor: const Color(0xFF9AD9B8),
220-
appBar: AppBar(
221-
backgroundColor: const Color(0xFF9AD9B8),
222-
elevation: 0,
223-
leading: IconButton(
224-
icon: const Icon(Icons.arrow_back),
225-
onPressed: () => Navigator.pop(context),
226-
),
216+
backgroundColor: AppColors.primaryGreen,
217+
appBar: CommonWidgets.buildAppBar(
218+
onBackPressed: () => Navigator.pop(context),
227219
),
228220
body: books.isEmpty
229221
? const Center(child: Text("추천 결과가 없습니다."))
@@ -262,7 +254,7 @@ class RecommendationResultScreen extends StatelessWidget {
262254

263255
Widget _buildBookCard(BuildContext context, dynamic book) {
264256
return Card(
265-
color: Color(0xFFF5F5DC),
257+
color: AppColors.lightCream,
266258
margin: const EdgeInsets.symmetric(vertical: 50),
267259
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
268260
child: Padding(
@@ -289,7 +281,7 @@ class RecommendationResultScreen extends StatelessWidget {
289281
book['cover'],
290282
style: GoogleFonts.jua(
291283
fontSize: 16,
292-
color: Color(0xFF037549),
284+
color: AppColors.darkGreen,
293285
),
294286
),
295287
],

0 commit comments

Comments
 (0)