Skip to content

Commit

Permalink
Merge pull request #1029 from Infomaniak/ai_animations
Browse files Browse the repository at this point in the history
feat(AIWriter): Improve animations of buttons and text
  • Loading branch information
PhilippeWeidmann committed Oct 9, 2023
2 parents 9a1e2a8 + b88ceff commit 6b297dd
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 35 deletions.
34 changes: 13 additions & 21 deletions Mail/Views/AI Writer/AIModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,11 @@ final class AIModel: ObservableObject {

func executeShortcut(_ shortcut: AIShortcutAction) async {
if shortcut == .edit {
withAnimation {
conversation.append(AIMessage(type: .assistant, content: MailResourcesStrings.Localizable.aiMenuEditRequest))
}
conversation.append(AIMessage(type: .assistant, content: MailResourcesStrings.Localizable.aiMenuEditRequest))
displayView(.prompt)
} else {
guard let contextId else { return }
withAnimation {
isLoading = true
}
isLoading = true
do {
let response = try await mailboxManager.apiFetcher.aiShortcut(contextId: contextId, shortcut: shortcut)
handleAIResponse(response)
Expand Down Expand Up @@ -100,25 +96,21 @@ final class AIModel: ObservableObject {
contextId = newContextId
}

withAnimation {
if let shortcutResponse = response as? AIShortcutResponse {
conversation.append(shortcutResponse.action)
}
conversation.append(AIMessage(type: .assistant, content: response.content))
isLoading = false
if let shortcutResponse = response as? AIShortcutResponse {
conversation.append(shortcutResponse.action)
}
conversation.append(AIMessage(type: .assistant, content: response.content))
isLoading = false
}

private func handleError(_ error: Error) {
withAnimation {
isLoading = false

if let mailApiError = error as? MailApiError,
mailApiError == .apiAIMaxSyntaxTokensReached || mailApiError == .apiAITooManyRequests {
self.error = mailApiError.localizedDescription
} else {
self.error = MailResourcesStrings.Localizable.aiErrorUnknown
}
isLoading = false

if let mailApiError = error as? MailApiError,
mailApiError == .apiAIMaxSyntaxTokensReached || mailApiError == .apiAITooManyRequests {
self.error = mailApiError.localizedDescription
} else {
self.error = MailResourcesStrings.Localizable.aiErrorUnknown
}
}
}
1 change: 0 additions & 1 deletion Mail/Views/AI Writer/AIProgressView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ struct AIProgressView: View {
.progressViewStyle(.circular)
.tint(MailResourcesAsset.aiColor.swiftUIColor)
}
.frame(height: UIConstants.buttonMediumHeight)
}
}

Expand Down
1 change: 0 additions & 1 deletion Mail/Views/AI Writer/AIPropositionMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ struct AIPropositionMenu: View {
.frame(width: 24, height: 24)
Text(MailResourcesStrings.Localizable.aiButtonRefine)
}
.frame(height: UIConstants.buttonMediumHeight)
}
.simultaneousGesture(TapGesture().onEnded {
matomo.track(eventWithCategory: .aiWriter, name: "refine")
Expand Down
8 changes: 2 additions & 6 deletions Mail/Views/AI Writer/AIPropositionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ struct AIPropositionView: View {
SelectableTextView(
textPlainHeight: $textPlainHeight,
text: aiModel.conversation.last?.content ?? "",
foregroundColor: aiModel.isLoading ? MailResourcesAsset.textTertiaryColor
.swiftUIColor : MailResourcesAsset
.textPrimaryColor.swiftUIColor
style: aiModel.isLoading ? .loading : .standard
)
.frame(height: textPlainHeight)
.tint(MailResourcesAsset.aiColor.swiftUIColor)
Expand All @@ -60,9 +58,7 @@ struct AIPropositionView: View {
.padding(.horizontal, value: .regular)
}
.onAppear {
withAnimation {
aiModel.isLoading = true
}
aiModel.isLoading = true
}
.task {
await aiModel.createConversation()
Expand Down
53 changes: 47 additions & 6 deletions Mail/Views/Thread/SelectableTextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,28 @@

import Foundation
import MailCore
import MailResources
import SwiftUI
import UIKit

struct SelectableTextView: UIViewRepresentable {
enum Style {
case loading, standard

var foregroundColor: UIColor {
switch self {
case .loading:
return MailResourcesAsset.textTertiaryColor.color
case .standard:
return MailResourcesAsset.textPrimaryColor.color
}
}
}

@Binding var textPlainHeight: CGFloat

let text: String?
var foregroundColor = MailTextStyle.body.color
var style = Style.standard

func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
Expand All @@ -34,20 +48,47 @@ struct SelectableTextView: UIViewRepresentable {
textView.isEditable = false
textView.textContainer.lineFragmentPadding = 0
textView.font = .systemFont(ofSize: 16)
textView.textColor = UIColor(foregroundColor)
textView.textColor = style.foregroundColor
textView.linkTextAttributes = [.underlineStyle: 1, .foregroundColor: UIColor.tintColor]
textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

return textView
}

func updateUIView(_ uiView: UITextView, context: Context) {
Task {
uiView.text = text
uiView.textColor = UIColor(foregroundColor)
// Replace text when the style is standard and the current color has not yet been changed
if style == .standard && uiView.textColor != style.foregroundColor {
replaceText(text: text ?? "", in: uiView)
} else {
insertText(text: text ?? "", in: uiView)
}
}

private func insertText(text: String, in uiView: UITextView) {
uiView.text = text
uiView.textColor = style.foregroundColor

computeViewHeight(uiView)
}

private func replaceText(text: String, in uiView: UITextView) {
UIView.animate(withDuration: 0.2) {
uiView.alpha = 0
} completion: { _ in
insertText(text: text, in: uiView)
UIView.animate(withDuration: 0.2) {
uiView.alpha = 1
}
}
}

private func computeViewHeight(_ uiView: UIView) {
Task {
await MainActor.run {
let sizeThatFits = uiView.sizeThatFits(CGSize(width: uiView.frame.width, height: CGFloat.greatestFiniteMagnitude))
let sizeThatFits = uiView.sizeThatFits(CGSize(
width: uiView.frame.width,
height: CGFloat.greatestFiniteMagnitude
))
textPlainHeight = sizeThatFits.height
}
}
Expand Down

0 comments on commit 6b297dd

Please sign in to comment.