ParaphrasingView.swift 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import SwiftUI
  2. struct ParaphrasingView: View {
  3. @StateObject private var viewModel = ParaphrasingViewModel()
  4. var body: some View {
  5. GeometryReader { proxy in
  6. let dynamicHorizontalPadding = min(max(proxy.size.width * 0.045, AppTheme.contentPadding), 52)
  7. let dynamicTopPadding = min(max(proxy.size.height * 0.05, 24), 44)
  8. let dynamicBottomPadding = min(max(proxy.size.height * 0.06, 28), 56)
  9. let dynamicEditorHeight = min(max(proxy.size.height * 0.43, 260), 560)
  10. ScrollView(.vertical, showsIndicators: false) {
  11. VStack(alignment: .leading, spacing: 0) {
  12. header
  13. .padding(.bottom, 28)
  14. contentCard(editorHeight: dynamicEditorHeight)
  15. .padding(.bottom, 24)
  16. GradientButton(title: "Paraphrase") {
  17. viewModel.paraphrase()
  18. }
  19. }
  20. .frame(maxWidth: 1200, alignment: .topLeading)
  21. .frame(maxWidth: .infinity, alignment: .topLeading)
  22. .padding(.horizontal, dynamicHorizontalPadding)
  23. .padding(.top, dynamicTopPadding)
  24. .padding(.bottom, dynamicBottomPadding)
  25. }
  26. }
  27. .onChange(of: viewModel.text) { newValue in
  28. if newValue.count > ParaphrasingViewModel.maxCharacters {
  29. viewModel.text = String(newValue.prefix(ParaphrasingViewModel.maxCharacters))
  30. }
  31. }
  32. }
  33. private var header: some View {
  34. HStack(alignment: .top) {
  35. VStack(alignment: .leading, spacing: 8) {
  36. Text("Paraphrasing")
  37. .font(.system(size: 30, weight: .bold))
  38. .foregroundStyle(AppTheme.textPrimary)
  39. HStack(spacing: 0) {
  40. Text("Say it ")
  41. .foregroundStyle(AppTheme.textSecondary)
  42. Text("differently")
  43. .fontWeight(.semibold)
  44. .foregroundStyle(AppTheme.teal)
  45. Text(". Keep it ")
  46. .foregroundStyle(AppTheme.textSecondary)
  47. Text("yours")
  48. .fontWeight(.semibold)
  49. .foregroundStyle(AppTheme.teal)
  50. Text(".")
  51. .foregroundStyle(AppTheme.textSecondary)
  52. }
  53. .font(.system(size: 15))
  54. }
  55. Spacer()
  56. IconButton {
  57. SettingsGearIcon()
  58. } action: {}
  59. .accessibilityLabel("Settings")
  60. }
  61. }
  62. private func contentCard(editorHeight: CGFloat) -> some View {
  63. VStack(alignment: .leading, spacing: 16) {
  64. Image("YourContentLogo")
  65. .resizable()
  66. .aspectRatio(contentMode: .fit)
  67. .frame(height: 52, alignment: .topLeading)
  68. .frame(height: 46, alignment: .topLeading)
  69. .clipped()
  70. .accessibilityLabel("Your Content")
  71. ZStack(alignment: .bottomTrailing) {
  72. ThinCaretTextEditor(text: $viewModel.text)
  73. .font(.system(size: 14))
  74. .foregroundStyle(AppTheme.textPrimary)
  75. .frame(minHeight: editorHeight, idealHeight: editorHeight)
  76. .background(Color.white)
  77. .clipShape(RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius))
  78. .overlay(
  79. RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
  80. .stroke(AppTheme.inputBorder, lineWidth: 1)
  81. )
  82. .overlay(alignment: .topLeading) {
  83. if viewModel.text.isEmpty {
  84. Text("Type or paste your text here and press the paraphrase button...")
  85. .font(.system(size: 14))
  86. .foregroundStyle(AppTheme.textMuted)
  87. .padding(.leading, AppTheme.textEditorHorizontalInset)
  88. .padding(.top, AppTheme.textEditorVerticalInset)
  89. .allowsHitTesting(false)
  90. }
  91. }
  92. Text(viewModel.characterCountLabel)
  93. .font(.system(size: 11))
  94. .foregroundStyle(AppTheme.textMuted)
  95. .padding(.trailing, 16)
  96. .padding(.bottom, 12)
  97. }
  98. HStack(spacing: 8) {
  99. ToolbarButton(title: "Paste Text", iconName: "doc.on.clipboard") {
  100. viewModel.pasteText()
  101. }
  102. ToolbarButton(title: "Upload File", iconName: "square.and.arrow.up") {}
  103. Spacer()
  104. ClearButton {
  105. viewModel.clearText()
  106. }
  107. }
  108. }
  109. .padding(22)
  110. .background(AppTheme.cardBackground)
  111. .clipShape(RoundedRectangle(cornerRadius: AppTheme.cardCornerRadius))
  112. .overlay(
  113. RoundedRectangle(cornerRadius: AppTheme.cardCornerRadius)
  114. .stroke(AppTheme.border, lineWidth: 1)
  115. )
  116. .shadow(color: AppTheme.cardShadow, radius: 16, y: 6)
  117. }
  118. }