Skip to content

Commit 33c370a

Browse files
committed
Add owner community controls and true milk lite mode
1 parent e3bc454 commit 33c370a

8 files changed

Lines changed: 655 additions & 160 deletions

File tree

apps/mobile/lib/core/theme/app_theme.dart

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ class AppTheme {
44
static const Color _bg = Color(0xFF000000);
55
static const Color _panel = Color(0xFF111111);
66
static const Color _accent = Color(0xFFFF2D55);
7-
static const Color _liteBg = Color(0xFF2F272B);
8-
static const Color _litePanel = Color(0xFF3B3238);
9-
static const Color _litePanelElevated = Color(0xFF4B4148);
10-
static const Color _liteAccent = Color(0xFFFF355E);
11-
static const Color _liteNeutral = Color(0xFFF4E7D8);
12-
static const Color _litePurple = Color(0xFFC4A7E7);
7+
static const Color _liteBg = Color(0xFFF7F1E8);
8+
static const Color _litePanel = Color(0xFFFFFAF3);
9+
static const Color _litePanelElevated = Color(0xFFF2E6D8);
10+
static const Color _liteAccent = Color(0xFFE11D48);
11+
static const Color _liteNeutral = Color(0xFF3D2B24);
12+
static const Color _liteSupporting = Color(0xFF8B1E3F);
1313

1414
static ThemeData get dark {
1515
final base = ThemeData.dark(useMaterial3: true);
@@ -44,14 +44,15 @@ class AppTheme {
4444
}
4545

4646
static ThemeData get lite {
47-
final base = ThemeData.dark(useMaterial3: true);
47+
final base = ThemeData.light(useMaterial3: true);
4848
final scheme = base.colorScheme.copyWith(
4949
surface: _litePanel,
5050
primary: _liteAccent,
51-
secondary: _liteNeutral,
52-
tertiary: _litePurple,
53-
onSurface: Colors.white,
51+
secondary: _liteSupporting,
52+
tertiary: _liteNeutral,
53+
onSurface: _liteNeutral,
5454
onPrimary: Colors.white,
55+
outline: _liteNeutral.withValues(alpha: 0.24),
5556
);
5657

5758
return base.copyWith(
@@ -60,7 +61,7 @@ class AppTheme {
6061
colorScheme: scheme,
6162
appBarTheme: const AppBarTheme(
6263
backgroundColor: _liteBg,
63-
foregroundColor: Colors.white,
64+
foregroundColor: _liteNeutral,
6465
centerTitle: false,
6566
),
6667
cardTheme: CardThemeData(
@@ -88,32 +89,38 @@ class AppTheme {
8889
fillColor: _litePanelElevated,
8990
border: OutlineInputBorder(
9091
borderRadius: BorderRadius.circular(14),
91-
borderSide: const BorderSide(color: Colors.white24),
92+
borderSide: BorderSide(color: _liteNeutral.withValues(alpha: 0.2)),
9293
),
9394
enabledBorder: OutlineInputBorder(
9495
borderRadius: BorderRadius.circular(14),
95-
borderSide: const BorderSide(color: Colors.white24),
96+
borderSide: BorderSide(color: _liteNeutral.withValues(alpha: 0.2)),
9697
),
9798
focusedBorder: OutlineInputBorder(
9899
borderRadius: BorderRadius.circular(14),
99100
borderSide: const BorderSide(color: _liteAccent),
100101
),
102+
labelStyle: const TextStyle(color: _liteNeutral),
103+
hintStyle: TextStyle(color: _liteNeutral.withValues(alpha: 0.58)),
101104
),
102105
switchTheme: SwitchThemeData(
103106
thumbColor: WidgetStateProperty.resolveWith<Color?>(
104-
(Set<WidgetState> states) => states.contains(WidgetState.selected)
105-
? _liteAccent
106-
: _liteNeutral,
107+
(Set<WidgetState> states) =>
108+
states.contains(WidgetState.selected) ? _liteAccent : _litePanel,
107109
),
108110
trackColor: WidgetStateProperty.resolveWith<Color?>(
109111
(Set<WidgetState> states) => states.contains(WidgetState.selected)
110112
? _liteAccent.withValues(alpha: 0.35)
111-
: Colors.white24,
113+
: _liteNeutral.withValues(alpha: 0.24),
112114
),
113115
),
116+
chipTheme: base.chipTheme.copyWith(
117+
backgroundColor: _litePanelElevated,
118+
side: BorderSide(color: _liteNeutral.withValues(alpha: 0.16)),
119+
labelStyle: const TextStyle(color: _liteNeutral),
120+
),
114121
textTheme: base.textTheme.apply(
115-
bodyColor: Colors.white,
116-
displayColor: Colors.white,
122+
bodyColor: _liteNeutral,
123+
displayColor: _liteNeutral,
117124
),
118125
);
119126
}

apps/mobile/lib/features/communities/data/community_edge_functions.dart

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ class CommunityEdgeFunctions {
1717
const CommunityEdgeFunctions(this._client);
1818

1919
final SupabaseClient _client;
20+
static const _communitySelectColumns =
21+
'id, name, join_code, category, is_private, created_at, description';
2022

2123
Future<Community> createCommunity({
2224
required String name,
@@ -211,9 +213,7 @@ class CommunityEdgeFunctions {
211213
Future<Community?> getCommunityById(String communityId) async {
212214
final result = await _client
213215
.from('communities')
214-
.select(
215-
'id, name, join_code, category, is_private, created_at, description',
216-
)
216+
.select(_communitySelectColumns)
217217
.eq('id', communityId)
218218
.maybeSingle();
219219

@@ -228,9 +228,7 @@ class CommunityEdgeFunctions {
228228
String? category,
229229
int limit = 50,
230230
}) async {
231-
var query = _client.from('communities').select(
232-
'id, name, join_code, category, is_private, created_at, description',
233-
);
231+
var query = _client.from('communities').select(_communitySelectColumns);
234232

235233
query = query.eq('is_private', false);
236234
final normalizedCategory = category?.trim().toLowerCase();
@@ -251,6 +249,64 @@ class CommunityEdgeFunctions {
251249
return rows.map(Community.fromMap).toList(growable: false);
252250
}
253251

252+
Future<Community> updateCommunity({
253+
required String communityId,
254+
required String name,
255+
String? description,
256+
required String category,
257+
required bool isPrivate,
258+
}) async {
259+
final normalizedName = name.trim();
260+
if (normalizedName.length < 2) {
261+
throw const CommunityApiException(
262+
'Community name must be at least 2 characters.',
263+
);
264+
}
265+
266+
final normalizedCategory = category.trim().toLowerCase();
267+
if (normalizedCategory.isEmpty) {
268+
throw const CommunityApiException('Category is required.');
269+
}
270+
271+
final normalizedDescription = description?.trim();
272+
273+
try {
274+
final row = await _client
275+
.from('communities')
276+
.update(
277+
<String, dynamic>{
278+
'name': normalizedName,
279+
'description': normalizedDescription?.isEmpty == true
280+
? null
281+
: normalizedDescription,
282+
'category': normalizedCategory,
283+
'is_private': isPrivate,
284+
},
285+
)
286+
.eq('id', communityId)
287+
.select(_communitySelectColumns)
288+
.single();
289+
290+
return Community.fromMap(Map<String, dynamic>.from(row as Map));
291+
} on PostgrestException catch (error) {
292+
throw CommunityApiException(error.message);
293+
} catch (_) {
294+
throw const CommunityApiException('Failed to update community.');
295+
}
296+
}
297+
298+
Future<void> deleteCommunity({
299+
required String communityId,
300+
}) async {
301+
try {
302+
await _client.from('communities').delete().eq('id', communityId);
303+
} on PostgrestException catch (error) {
304+
throw CommunityApiException(error.message);
305+
} catch (_) {
306+
throw const CommunityApiException('Failed to delete community.');
307+
}
308+
}
309+
254310
Future<List<TrendingCommunitySpotlight>> listTrendingPublicCommunities({
255311
int limit = 8,
256312
int lookbackHours = 24,

0 commit comments

Comments
 (0)