Skip to content

Commit 48b112d

Browse files
committed
✨ Enhance AI Input and Quick Actions:
- Add auto-focus feature for AI input when activated. - Improve animations for AI input and quick actions. - Redesign AI button with better visual feedback and dynamic states. - Introduce modern quick actions with categorized options for writing and content enhancement. - Fix hotkey conflicts and improve focus management.
1 parent 8d35e2a commit 48b112d

5 files changed

Lines changed: 579 additions & 52 deletions

File tree

releases/v1.1.3/RELEASE_NOTES.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Remi v1.1.3 Release Notes
2+
3+
## 🎯 Major Improvements
4+
5+
### ✨ Enhanced AI Input Experience
6+
- **Auto-Focus**: AI input now automatically focuses when activated - simply click the AI button and start typing immediately
7+
- **Smooth Animations**: Redesigned slide-up/slide-down animations with spring physics for premium feel
8+
- **Visual Feedback**: AI button now provides better visual states (active/inactive) with enhanced shadows and gradients
9+
- **Better Timing**: Optimized focus timing to work seamlessly with animations
10+
11+
### 🔧 Hotkey Conflict Fix
12+
- **System-Wide Fix**: Resolved Command+Shift+C conflict with other applications (browsers, etc.)
13+
- **Local Shortcuts**: Copy shortcut now works locally within Remi when focused, respecting system app focus
14+
- **Better UX**: Other apps can now use their native shortcuts without interference from Remi
15+
16+
## 🎨 UI/UX Improvements
17+
18+
### Modern AI Button Design
19+
- Dynamic icon changes based on state
20+
- Enhanced gradient backgrounds with depth
21+
- Hierarchical symbol rendering for iOS-style polish
22+
- Improved shadow effects and scaling feedback
23+
24+
### Refined Animations
25+
- Spring-based animations for natural feel
26+
- Asymmetric transitions (different entrance/exit animations)
27+
- Optimized timing for smoother interactions
28+
- Scale and opacity combinations for premium polish
29+
30+
## 🔧 Technical Improvements
31+
- Better focus state management between parent and child components
32+
- Improved animation coordination
33+
- Enhanced component communication patterns
34+
- More responsive UI interactions
35+
36+
## 🐛 Bug Fixes
37+
- Fixed global hotkey conflicts with system applications
38+
- Resolved AI input focus issues
39+
- Improved animation consistency
40+
- Better error handling in focus management
41+
42+
---
43+
44+
**This release focuses on user experience refinements and resolving system conflicts. The AI assistant is now more intuitive and responsive, while ensuring Remi plays nicely with other applications.**

remi/UI/Views/Components/AIInputView.swift

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import SwiftUI
22

33
struct AIInputView: View {
44
@Binding var isVisible: Bool
5+
@Binding var shouldFocus: Bool // New focus trigger from parent
56
var onSend: (String) -> Void
67

78
@State private var inputText: String = ""
89
@State private var isProcessing: Bool = false
910
@FocusState private var isFocused: Bool
11+
@State private var focusProtectionTimer: Timer? // Protect focus from being stolen
1012
@ObservedObject private var settingsManager = SettingsManager.shared
1113

1214
private var isAPIKeyConfigured: Bool {
@@ -16,7 +18,36 @@ struct AIInputView: View {
1618

1719
var body: some View {
1820
Themed { theme in
19-
VStack(spacing: 8) {
21+
VStack(spacing: 12) {
22+
// Header with close button for center modal
23+
HStack {
24+
VStack(alignment: .leading, spacing: 2) {
25+
Text("AI Assistant")
26+
.font(.system(size: 16, weight: .semibold))
27+
.foregroundColor(theme.textPrimary)
28+
29+
Text("Describe how you'd like to improve your content")
30+
.font(.system(size: 12, weight: .medium))
31+
.foregroundColor(theme.textSecondary)
32+
}
33+
34+
Spacer()
35+
36+
Button(action: {
37+
withAnimation(.easeInOut(duration: 0.2)) {
38+
isVisible = false
39+
}
40+
}) {
41+
Image(systemName: "xmark.circle.fill")
42+
.font(.system(size: 18, weight: .medium))
43+
.foregroundColor(theme.textSecondary.opacity(0.6))
44+
.background(Color.clear)
45+
}
46+
.buttonStyle(.plain)
47+
.help("Close AI Assistant")
48+
}
49+
50+
VStack(spacing: 8) {
2051
// API Key warning (if needed) - minimal
2152
if !isAPIKeyConfigured {
2253
HStack(spacing: 4) {
@@ -73,24 +104,51 @@ struct AIInputView: View {
73104
RoundedRectangle(cornerRadius: 12)
74105
.stroke(isFocused ? theme.accent.opacity(0.5) : theme.border, lineWidth: 1)
75106
)
107+
}
76108
}
77-
.padding(10)
109+
.padding(16)
78110
.background(
79111
RoundedRectangle(cornerRadius: 16)
80112
.fill(theme.background)
81-
.shadow(color: Color.black.opacity(0.1), radius: 8, x: 0, y: 4)
113+
.shadow(color: Color.black.opacity(0.15), radius: 12, x: 0, y: 8)
114+
)
115+
.overlay(
116+
RoundedRectangle(cornerRadius: 16)
117+
.stroke(theme.border.opacity(0.1), lineWidth: 1)
82118
)
83119
.onAppear {
120+
// Focus immediately on appear if API key is configured
84121
if isAPIKeyConfigured {
85-
isFocused = true
122+
isFocused = true
123+
startFocusProtection()
124+
}
125+
}
126+
.onChange(of: shouldFocus) { _, newValue in
127+
if newValue && isAPIKeyConfigured {
128+
// Parent triggered focus - apply immediately and reset trigger
129+
isFocused = true
130+
shouldFocus = false
131+
startFocusProtection()
86132
}
87133
}
88134
.onChange(of: isVisible) { _, newValue in
89-
if !newValue {
135+
if newValue {
136+
// When becoming visible, ensure focus
137+
if isAPIKeyConfigured {
138+
isFocused = true
139+
startFocusProtection()
140+
}
141+
} else {
142+
// When hiding, clean up state
90143
inputText = ""
91144
isProcessing = false
145+
isFocused = false
146+
stopFocusProtection()
92147
}
93148
}
149+
.onDisappear {
150+
stopFocusProtection()
151+
}
94152
.transition(.scale(scale: 0.95).combined(with: .opacity))
95153
}
96154
}
@@ -104,6 +162,7 @@ struct AIInputView: View {
104162

105163
let prompt = inputText.trimmingCharacters(in: .whitespacesAndNewlines)
106164
isProcessing = true
165+
stopFocusProtection() // Stop protection while processing
107166
onSend(prompt)
108167
inputText = ""
109168

@@ -115,6 +174,21 @@ struct AIInputView: View {
115174
}
116175
}
117176
}
177+
178+
// Focus protection methods to prevent focus stealing from rerenders
179+
private func startFocusProtection() {
180+
stopFocusProtection() // Clear any existing timer
181+
focusProtectionTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { _ in
182+
if isVisible && isAPIKeyConfigured && !isProcessing && !isFocused {
183+
isFocused = true
184+
}
185+
}
186+
}
187+
188+
private func stopFocusProtection() {
189+
focusProtectionTimer?.invalidate()
190+
focusProtectionTimer = nil
191+
}
118192
}
119193

120194
// Notification for opening settings

remi/UI/Views/Components/IntegratedSettingsView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ struct IntegratedSettingsView: View {
333333
.font(.body)
334334
.foregroundColor(theme.textSecondary)
335335
Spacer()
336-
Text("1.1.0")
336+
Text("1.1.3")
337337
.font(.body)
338338
.fontWeight(.semibold)
339339
.foregroundColor(theme.textPrimary)

0 commit comments

Comments
 (0)