Skip to content

Commit 96a5954

Browse files
committed
Customized items for the GridViews and ListViews
1 parent b7c917b commit 96a5954

1 file changed

Lines changed: 182 additions & 0 deletions

File tree

lib/code_judge_list_items.dart

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/// Copyright 2026 Fabian Roland (naibaf-1)
2+
3+
/// Licensed under the Apache License, Version 2.0 (the "License");
4+
/// you may not use this file except in compliance with the License.
5+
/// You may obtain a copy of the License at
6+
7+
/// http://www.apache.org/licenses/LICENSE-2.0
8+
9+
/// Unless required by applicable law or agreed to in writing, software
10+
/// distributed under the License is distributed on an "AS IS" BASIS,
11+
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
/// See the License for the specific language governing permissions and
13+
/// limitations under the License.
14+
library;
15+
16+
import 'package:flutter/material.dart';
17+
18+
// Styled item for the GridView
19+
class CodeJudgeDesktopAndTabletItem extends StatelessWidget{
20+
final String title;
21+
final VoidCallback onTap;
22+
final ValueChanged<TapDownDetails>? onLongPress;
23+
final ValueChanged<TapUpDetails>? onRightClick;
24+
final ValueChanged<Offset>? onMenuClick;
25+
final String note;
26+
27+
const CodeJudgeDesktopAndTabletItem({
28+
super.key,
29+
required this.title,
30+
required this.onTap,
31+
this.onLongPress,
32+
this.onRightClick,
33+
this.onMenuClick,
34+
this.note = "",
35+
});
36+
37+
@override
38+
Widget build(BuildContext context) {
39+
final theme = Theme.of(context);
40+
TapDownDetails? tapDetails;
41+
final GlobalKey buttonKey = GlobalKey();
42+
43+
return Material(
44+
borderRadius: BorderRadius.circular(12),
45+
color: theme.colorScheme.surfaceContainerLow,
46+
child: InkWell(
47+
onTap: onTap,
48+
onTapDown: (details) { // Register each tap and store its position
49+
tapDetails = details;
50+
},
51+
onLongPress: () {
52+
if (tapDetails != null && onLongPress != null) {
53+
onLongPress!.call(tapDetails!);
54+
}
55+
},
56+
onSecondaryTapUp: onRightClick != null
57+
? (details) => onRightClick!.call(details)
58+
: null,
59+
borderRadius: BorderRadius.circular(12),
60+
splashColor: theme.colorScheme.primary.withAlpha(32), // Ripple-color at click
61+
hoverColor: theme.colorScheme.tertiary.withAlpha(32), // Hover-color
62+
child: Container(
63+
alignment: Alignment.center,
64+
child: Stack(
65+
children: [
66+
Positioned(
67+
top: 2,
68+
right: 2,
69+
child: IconButton(
70+
key: buttonKey,
71+
onPressed: () {
72+
// Get the position of the button
73+
final RenderBox button = buttonKey.currentContext!.findRenderObject() as RenderBox;
74+
Offset position = button.localToGlobal(Offset.zero,);
75+
76+
if (onMenuClick != null) {
77+
onMenuClick!.call(position);
78+
}
79+
},
80+
icon: Icon(
81+
Icons.more_vert_outlined,
82+
size: 20,
83+
),
84+
),
85+
),
86+
Center(
87+
child: Text(title, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold))
88+
),
89+
Positioned(
90+
bottom: 12,
91+
right: 18,
92+
child: Text(note, style: TextStyle(fontSize: 12, fontWeight: FontWeight.w300))
93+
),
94+
],
95+
)
96+
),
97+
),
98+
);
99+
}
100+
}
101+
// Styled item for the ListView
102+
class CodeJudgeMobileItem extends StatelessWidget {
103+
final String title;
104+
final VoidCallback onTap;
105+
final ValueChanged<TapDownDetails>? onLongPress;
106+
final ValueChanged<TapUpDetails>? onRightClick;
107+
final ValueChanged<Offset>? onMenuClick;
108+
final String note;
109+
110+
const CodeJudgeMobileItem({
111+
super.key,
112+
required this.title,
113+
required this.onTap,
114+
this.onLongPress,
115+
this.onRightClick,
116+
this.onMenuClick,
117+
this.note = "",
118+
});
119+
120+
@override
121+
Widget build(BuildContext context) {
122+
final theme = Theme.of(context);
123+
TapDownDetails? tapDetails;
124+
final GlobalKey buttonKey = GlobalKey();
125+
126+
return Material(
127+
borderRadius: BorderRadius.circular(12),
128+
color: theme.colorScheme.surfaceContainerLow,
129+
child: InkWell(
130+
onTap: onTap,
131+
onTapDown: (details) { // Register each tap and store its position
132+
tapDetails = details;
133+
},
134+
onLongPress: () {
135+
if (tapDetails != null && onLongPress != null) {
136+
onLongPress!.call(tapDetails!);
137+
}
138+
},
139+
onSecondaryTapUp: onRightClick != null
140+
? (details) => onRightClick!.call(details)
141+
: null,
142+
borderRadius: BorderRadius.circular(12),
143+
splashColor: theme.colorScheme.primary.withAlpha(32),
144+
hoverColor: theme.colorScheme.tertiary.withAlpha(32),
145+
child: Container(
146+
padding: const EdgeInsets.all(8.0),
147+
alignment: Alignment.centerLeft,
148+
child: Row(
149+
children: [
150+
Expanded(
151+
child: Padding(
152+
padding: const EdgeInsets.only(left: 8.0),
153+
child: Text(title, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
154+
),
155+
),
156+
Padding(
157+
padding: const EdgeInsets.only(right: 8.0),
158+
child: Text(note, style: TextStyle(fontSize: 12, fontWeight: FontWeight.w200)),
159+
),
160+
IconButton(
161+
key: buttonKey,
162+
onPressed: () {
163+
// Get the position of the button
164+
final RenderBox button = buttonKey.currentContext!.findRenderObject() as RenderBox;
165+
Offset position = button.localToGlobal(Offset.zero,);
166+
167+
if (onMenuClick != null) {
168+
onMenuClick!.call(position);
169+
}
170+
},
171+
icon: Icon(
172+
Icons.more_vert_outlined,
173+
size: 20,
174+
),
175+
),
176+
],
177+
)
178+
),
179+
),
180+
);
181+
}
182+
}

0 commit comments

Comments
 (0)