mirror of
https://github.com/block/buzz.git
synced 2026-10-27 04:30:52 +00:00
## Summary Preview buzz-app's Tabler icon style in the mobile app, replacing app-drawn Lucide glyphs across channels, messages, activity, search, and settings. A shared `BuzzIcons` mapping uses the bundled Tabler 3.46.0 outline font, matching buzz-app's version, with its MIT license and source documented. Native UIKit controls retain SF Symbols. The former 300/500 navigation glyphs use Tabler's standard outline; existing selection colors and labels remain. ### Related issue No matching Tabler mobile migration issue or PR found. Related native iOS controls: #8055. ### Testing - Pre-push mobile analysis, formatting, file-size checks, and the full mobile test suite passed. - 194 focused widget tests passed, including channels, home, search, settings, and message content. - Light and dark community-settings renders inspected. - Signed iPhone Release build succeeded; installed and launched as Buzz Tabler on a physical iPhone. - Full `just ci` attempted; stopped during Rust clippy compilation because the Mac ran low on disk space. Full repository validation is not claimed. Signed-off-by: kenny lopez <klopez4212@gmail.com>
128 lines
4.4 KiB
Dart
128 lines
4.4 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||
import 'package:buzz/shared/theme/buzz_icons.dart';
|
||
|
||
import '../theme/theme.dart';
|
||
import '../widgets/sheet_action_section.dart';
|
||
import '../widgets/modal_presentation.dart';
|
||
import 'reminder_service.dart';
|
||
import 'reminder_time_presets.dart';
|
||
|
||
/// Bottom sheet for "Remind me later": desktop-parity presets plus a native
|
||
/// date/time picker, publishing the same author-private kind-30300 reminder
|
||
/// events desktop reads.
|
||
void showRemindMeLaterSheet({
|
||
required BuildContext context,
|
||
required WidgetRef ref,
|
||
required ReminderTarget target,
|
||
}) {
|
||
final service = ref.read(reminderServiceProvider);
|
||
final messenger = ScaffoldMessenger.of(context);
|
||
if (service == null) {
|
||
messenger.showSnackBar(
|
||
const SnackBar(content: Text('Sign in to set reminders')),
|
||
);
|
||
return;
|
||
}
|
||
|
||
Future<void> submit(int notBefore) async {
|
||
try {
|
||
await service.createReminder(target: target, notBefore: notBefore);
|
||
messenger.showSnackBar(const SnackBar(content: Text('Reminder set')));
|
||
} catch (error) {
|
||
// Stable user-facing copy; the relay/crypto detail goes to the log.
|
||
debugPrint('[RemindMeLater] createReminder failed: $error');
|
||
messenger.showSnackBar(
|
||
const SnackBar(content: Text('Couldn’t set reminder. Try again.')),
|
||
);
|
||
}
|
||
}
|
||
|
||
showBuzzModalBottomSheet<void>(
|
||
context: context,
|
||
title: 'Remind me about this message',
|
||
showDragHandle: true,
|
||
builder: (sheetContext) => SafeArea(
|
||
child: IconTheme.merge(
|
||
data: const IconThemeData(size: 22),
|
||
child: SingleChildScrollView(
|
||
child: Padding(
|
||
padding: const EdgeInsets.fromLTRB(
|
||
Grid.gutter,
|
||
0,
|
||
Grid.gutter,
|
||
Grid.xs,
|
||
),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
SheetActionSection(
|
||
children: [
|
||
for (final preset in reminderTimePresets)
|
||
ListTile(
|
||
leading: const Icon(BuzzIcons.clock),
|
||
title: Text(preset.label),
|
||
onTap: () {
|
||
Navigator.of(sheetContext).pop();
|
||
submit(preset.getTimestamp());
|
||
},
|
||
),
|
||
],
|
||
),
|
||
SheetActionSection(
|
||
children: [
|
||
ListTile(
|
||
leading: const Icon(BuzzIcons.calendarClock),
|
||
title: const Text('Pick a date & time'),
|
||
onTap: () async {
|
||
final navigator = Navigator.of(sheetContext);
|
||
final timestamp = await _pickCustomDateTime(context);
|
||
// Cancelled or not-in-the-future: keep the preset sheet
|
||
// open so retrying doesn't mean long-pressing again.
|
||
if (timestamp == null) return;
|
||
if (navigator.mounted) navigator.pop();
|
||
await submit(timestamp);
|
||
},
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
/// Native date + time pickers chained together. Returns a future Unix
|
||
/// timestamp in seconds, or null when cancelled or not in the future.
|
||
Future<int?> _pickCustomDateTime(BuildContext context) async {
|
||
final now = DateTime.now();
|
||
final date = await showBuzzDialog<DateTime>(
|
||
context: context,
|
||
builder: (_) => DatePickerDialog(
|
||
initialDate: now,
|
||
firstDate: DateTime(now.year, now.month, now.day),
|
||
lastDate: now.add(const Duration(days: 365 * 2)),
|
||
),
|
||
);
|
||
if (date == null || !context.mounted) return null;
|
||
|
||
final time = await showBuzzDialog<TimeOfDay>(
|
||
context: context,
|
||
builder: (_) =>
|
||
const TimePickerDialog(initialTime: TimeOfDay(hour: 9, minute: 0)),
|
||
);
|
||
if (time == null) return null;
|
||
|
||
final timestamp = combineCustomDateTime(date, time.hour, time.minute);
|
||
if (timestamp == null && context.mounted) {
|
||
ScaffoldMessenger.of(
|
||
context,
|
||
).showSnackBar(const SnackBar(content: Text('Pick a time in the future')));
|
||
}
|
||
return timestamp;
|
||
}
|