diff --git a/scribe/lib/scribe/ai/presentation/widgets/ai_scribe.dart b/scribe/lib/scribe/ai/presentation/widgets/ai_scribe.dart index 31c6ba778..48effa947 100644 --- a/scribe/lib/scribe/ai/presentation/widgets/ai_scribe.dart +++ b/scribe/lib/scribe/ai/presentation/widgets/ai_scribe.dart @@ -67,10 +67,16 @@ Future showAIScribeDialog({ ); if (buttonPosition != null) { + final categories = availableCategories ?? AIScribeMenuCategory.values; + final modalHeight = hasContent + ? (categories.length * AIScribeSizes.menuItemHeight) + AIScribeSizes.fieldSpacing + AIScribeSizes.barHeight + : AIScribeSizes.barHeight; + final position = calculateModalPosition( context: context, buttonPosition: buttonPosition, modalWidth: AIScribeSizes.barWidth, + modalHeight: modalHeight, ); return PointerInterceptor( @@ -158,6 +164,15 @@ Future showAIScribeDialog({ ); } +double calculateMenuDialogHeight({ + required bool hasContent, + required int categoryCount, +}) { + return hasContent + ? (categoryCount * AIScribeSizes.menuItemHeight) + AIScribeSizes.fieldSpacing + AIScribeSizes.barHeight + : AIScribeSizes.barHeight; +} + ({double left, double bottom}) calculateModalPosition({ required BuildContext context, required Offset buttonPosition, diff --git a/scribe/test/scribe/ai/presentation/widgets/ai_scribe_test.dart b/scribe/test/scribe/ai/presentation/widgets/ai_scribe_test.dart index 1a2cf7acb..4089af2b5 100644 --- a/scribe/test/scribe/ai/presentation/widgets/ai_scribe_test.dart +++ b/scribe/test/scribe/ai/presentation/widgets/ai_scribe_test.dart @@ -4,7 +4,66 @@ import 'package:scribe/scribe/ai/presentation/styles/ai_scribe_styles.dart'; import 'package:scribe/scribe/ai/presentation/widgets/ai_scribe.dart'; void main() { - group('calculateModalPosition::', () { + group('calculateMenuDialogHeight::', () { + test('should calculate correct height with content and default 4 categories', () { + // Arrange + const hasContent = true; + const categoryCount = 4; + + // Act + final height = calculateMenuDialogHeight( + hasContent: hasContent, + categoryCount: categoryCount, + ); + + // Assert + // 4 categories × 40px + 8px spacing + 48px bar = 216px + const expectedHeight = (4 * AIScribeSizes.menuItemHeight) + + AIScribeSizes.fieldSpacing + + AIScribeSizes.barHeight; + expect(height, expectedHeight); + expect(height, 216.0); + }); + + test('should calculate correct height with content and custom categories', () { + // Arrange + const hasContent = true; + const categoryCount = 2; + + // Act + final height = calculateMenuDialogHeight( + hasContent: hasContent, + categoryCount: categoryCount, + ); + + // Assert + // 2 categories × 40px + 8px spacing + 48px bar = 136px + const expectedHeight = (2 * AIScribeSizes.menuItemHeight) + + AIScribeSizes.fieldSpacing + + AIScribeSizes.barHeight; + expect(height, expectedHeight); + expect(height, 136.0); + }); + + test('should calculate correct height without content (bar only)', () { + // Arrange + const hasContent = false; + const categoryCount = 4; // Should be ignored when hasContent is false + + // Act + final height = calculateMenuDialogHeight( + hasContent: hasContent, + categoryCount: categoryCount, + ); + + // Assert + // Only the bar height + expect(height, AIScribeSizes.barHeight); + expect(height, 48.0); + }); + }); + + group('calculateModalPosition::', () { testWidgets('should adjust left position when modal would go off-screen to the right', (tester) async { // Arrange const screenSize = Size(800, 600);