flutter-dev 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
managers/mirror.py ADDED
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Mirror Manager - scrcpy and wireless ADB functions
4
+ """
5
+
6
+ import shutil
7
+ import subprocess
8
+
9
+ from common_utils import (
10
+ RED, GREEN, YELLOW, BLUE, NC,
11
+ is_windows, is_macos, is_linux,
12
+ )
13
+ from core.constants import PATTERNS
14
+ from core.state import get_selected_device, set_selected_device, clear_selected_device
15
+ from managers.device import (
16
+ get_usb_devices,
17
+ ensure_device_connected,
18
+ build_adb_cmd,
19
+ )
20
+
21
+
22
+ def select_usb_device_for_wireless():
23
+ """
24
+ Prompt user to select a USB device if multiple are connected.
25
+ Sets the selected device.
26
+ Returns: True if device selected/available, False if no devices
27
+ """
28
+ devices = get_usb_devices()
29
+
30
+ if not devices:
31
+ return False
32
+
33
+ if len(devices) == 1:
34
+ # Only one USB device, auto-select it
35
+ set_selected_device(devices[0])
36
+ return True
37
+
38
+ # Multiple USB devices found, ask user to select
39
+ print(f"\n{YELLOW}Multiple USB devices detected:{NC}")
40
+ for i, device in enumerate(devices, 1):
41
+ print(f" {i}. {device}")
42
+
43
+ print()
44
+ while True:
45
+ try:
46
+ choice = input(f"Select USB device (1-{len(devices)}): ").strip()
47
+ index = int(choice) - 1
48
+ if 0 <= index < len(devices):
49
+ set_selected_device(devices[index])
50
+ print(f"{GREEN}✓ Selected: {devices[index]}{NC}\n")
51
+ return True
52
+ else:
53
+ print(f"{RED}Invalid choice. Please enter a number between 1 and {len(devices)}{NC}")
54
+ except ValueError:
55
+ print(f"{RED}Invalid input. Please enter a number{NC}")
56
+ except KeyboardInterrupt:
57
+ print(f"\n{YELLOW}Selection cancelled{NC}")
58
+ return False
59
+
60
+
61
+ def setup_wireless_adb():
62
+ """
63
+ Setup wireless ADB connection
64
+ Guides user through connecting device wirelessly
65
+ """
66
+ print(f"{YELLOW}Setting up Wireless ADB...{NC}\n")
67
+
68
+ # Check if USB device is connected and select it
69
+ if not select_usb_device_for_wireless():
70
+ print(f"{RED}Error: No device connected via USB!{NC}")
71
+ print(f"{YELLOW}Please connect your device via USB first{NC}")
72
+ return False
73
+
74
+ selected_device = get_selected_device()
75
+ print(f"{GREEN}✓ Device found: {selected_device}{NC}")
76
+ print(f"\n{BLUE}Step 1: Getting device IP address...{NC}")
77
+
78
+ # Get device IP address
79
+ try:
80
+ result = subprocess.run(
81
+ build_adb_cmd(["shell", "ip", "addr", "show", "wlan0"]),
82
+ capture_output=True,
83
+ text=True,
84
+ encoding='utf-8',
85
+ errors='replace',
86
+ timeout=5
87
+ )
88
+
89
+ if result.returncode == 0:
90
+ # Extract IP address
91
+ match = PATTERNS['ip_address'].search(result.stdout)
92
+ if match:
93
+ device_ip = match.group(1)
94
+ print(f"{GREEN}Device IP: {device_ip}{NC}")
95
+ else:
96
+ print(f"{RED}Could not detect IP address{NC}")
97
+ device_ip = input(f"Enter device IP address manually: ")
98
+ else:
99
+ device_ip = input(f"Enter device IP address: ")
100
+ except Exception:
101
+ device_ip = input(f"Enter device IP address: ")
102
+
103
+ if not device_ip:
104
+ print(f"{RED}IP address required!{NC}")
105
+ return False
106
+
107
+ print(f"\n{BLUE}Step 2: Setting up ADB on port 5555...{NC}")
108
+ # Enable TCP/IP mode on port 5555
109
+ result = subprocess.run(
110
+ build_adb_cmd(["tcpip", "5555"]),
111
+ capture_output=True,
112
+ text=True,
113
+ encoding='utf-8',
114
+ errors='replace'
115
+ )
116
+
117
+ if result.returncode != 0:
118
+ print(f"{RED}Failed to enable TCP/IP mode{NC}")
119
+ print(f"{YELLOW}Error: {result.stderr}{NC}")
120
+ return False
121
+
122
+ print(f"{GREEN}✓ TCP/IP mode enabled{NC}")
123
+ print(f"\n{YELLOW}You can now disconnect the USB cable{NC}")
124
+ input("Press Enter after disconnecting USB cable...")
125
+
126
+ # Clear selected device since we're switching to wireless
127
+ clear_selected_device()
128
+
129
+ print(f"\n{BLUE}Step 3: Connecting to {device_ip}:5555...{NC}")
130
+ # Connect to device wirelessly (don't use device selection for connect command)
131
+ result = subprocess.run(
132
+ ["adb", "connect", f"{device_ip}:5555"],
133
+ capture_output=True,
134
+ text=True,
135
+ encoding='utf-8',
136
+ errors='replace'
137
+ )
138
+
139
+ if result.returncode == 0 and "connected" in result.stdout.lower():
140
+ print(f"{GREEN}✓ Wireless ADB connected successfully!{NC}")
141
+ print(f"\n{BLUE}Device: {device_ip}:5555{NC}")
142
+ print(f"\n{YELLOW}To disconnect: adb disconnect{NC}")
143
+ print(f"{YELLOW}To reconnect via USB: adb usb{NC}")
144
+ return True
145
+ else:
146
+ print(f"{RED}Failed to connect wirelessly{NC}")
147
+ print(f"{YELLOW}Output: {result.stdout}{NC}")
148
+ return False
149
+
150
+
151
+ def launch_scrcpy(always_on_top=True):
152
+ """
153
+ Launch scrcpy with optimized settings
154
+
155
+ Args:
156
+ always_on_top: If True, keep the scrcpy window always on top
157
+ """
158
+ print(f"{YELLOW}Launching scrcpy...{NC}\n")
159
+
160
+ # Check if scrcpy is installed (cross-platform)
161
+ scrcpy_path = shutil.which("scrcpy")
162
+ if not scrcpy_path:
163
+ print(f"{RED}Error: scrcpy not found!{NC}")
164
+ if is_windows():
165
+ print(f"{YELLOW}Install: scoop install scrcpy OR choco install scrcpy{NC}")
166
+ elif is_macos():
167
+ print(f"{YELLOW}Install: brew install scrcpy{NC}")
168
+ else:
169
+ print(f"{YELLOW}Install: sudo apt install scrcpy OR sudo snap install scrcpy{NC}")
170
+ return False
171
+
172
+ # Check for connected device and select if multiple
173
+ if not ensure_device_connected(
174
+ "No device connected!",
175
+ "Connect device via USB or use 'fdev mirror --wireless' for wireless setup"
176
+ ):
177
+ return False
178
+
179
+ selected_device = get_selected_device()
180
+ print(f"{GREEN}✓ Device found: {selected_device}{NC}")
181
+
182
+ # Build scrcpy command with optimized settings
183
+ cmd = ["scrcpy", "-s", selected_device, "--no-mouse-hover", "-m", "1080", "-b", "5M"]
184
+ if always_on_top:
185
+ cmd.insert(4, "--always-on-top")
186
+
187
+ print(f"\n{BLUE}Launching scrcpy...{NC}")
188
+ print(f"{YELLOW}Command: {' '.join(cmd)}{NC}\n")
189
+
190
+ try:
191
+ # Launch scrcpy (blocking call)
192
+ result = subprocess.run(cmd)
193
+
194
+ if result.returncode == 0:
195
+ print(f"\n{GREEN}✓ scrcpy closed successfully{NC}")
196
+ return True
197
+ else:
198
+ print(f"\n{YELLOW}scrcpy exited with code {result.returncode}{NC}")
199
+ return False
200
+ except KeyboardInterrupt:
201
+ print(f"\n{YELLOW}scrcpy interrupted by user{NC}")
202
+ return False
203
+ except Exception as e:
204
+ print(f"{RED}Error launching scrcpy: {e}{NC}")
205
+ return False
managers/project.py ADDED
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Project Manager - Setup, cleanup, build_runner, pods functions
4
+ """
5
+
6
+ import os
7
+ import sys
8
+ import subprocess
9
+ from pathlib import Path
10
+
11
+ from common_utils import (
12
+ RED, GREEN, YELLOW,BLUE, NC, CHECKMARK,
13
+ timer_decorator,
14
+ is_windows,
15
+ )
16
+ from managers.build import run_flutter_command
17
+
18
+
19
+ def generate_lang():
20
+ """Generate localization files"""
21
+ # Run flutter gen-l10n to generate localization files
22
+ run_flutter_command(["flutter", "gen-l10n"], "Generating localizations ")
23
+ print(f"\n{CHECKMARK} Localizations generated successfully.")
24
+
25
+
26
+ def run_build_runner():
27
+ """Run build_runner to generate Dart code"""
28
+ print(f"{YELLOW}Executing build_runner...{NC} \n")
29
+ run_flutter_command(["dart", "run", "build_runner", "build", "--delete-conflicting-outputs"], "Running build_runner ")
30
+
31
+
32
+ @timer_decorator
33
+ def full_setup():
34
+ """Perform full project setup"""
35
+ print(f"{YELLOW}Performing full setup...{NC} \n")
36
+ # Clean the project
37
+ run_flutter_command(["flutter", "clean"], "Cleaning project... ")
38
+ # Upgrade dependencies
39
+ run_flutter_command(["flutter", "pub", "upgrade"], "Upgrading dependencies... ")
40
+ # Run build_runner
41
+ run_flutter_command(["dart", "run", "build_runner", "build", "--delete-conflicting-outputs"], "Running build_runner... ")
42
+ # Generate localizations
43
+ run_flutter_command(["flutter", "gen-l10n"], "Generating localizations... ")
44
+ # Refresh dependencies
45
+ run_flutter_command(["flutter", "pub", "upgrade"], "Refreshing dependencies... ")
46
+ # Analyze code
47
+ run_flutter_command(["flutter", "analyze"], "Analyzing code... ")
48
+ # Format code
49
+ run_flutter_command(["dart", "format", "."], "Formatting code... ")
50
+ print(f"\n {GREEN}✓ Full setup completed successfully. {NC}")
51
+
52
+
53
+ def repair_cache():
54
+ """Repair pub cache"""
55
+ print(f"{YELLOW}Repairing pub cache...{NC}\n")
56
+ run_flutter_command(["flutter", "pub", "cache", "repair"], "Repairing pub cache... ")
57
+ print(f"\n {GREEN}✓ Pub cache repaired successfully. {NC}")
58
+
59
+
60
+ @timer_decorator
61
+ def cleanup_project():
62
+ """Clean up project"""
63
+ print(f"{YELLOW}Cleaning up project...{NC}\n")
64
+ run_flutter_command(["flutter", "clean"], "Cleaning project... ")
65
+ # Get dependencies
66
+ run_flutter_command(["flutter", "pub", "get"], "Getting dependencies... ")
67
+
68
+ # fix code Issues
69
+ run_flutter_command(["dart", "fix", "--apply"], "Fixing code issues... ")
70
+
71
+ # Format code
72
+ run_flutter_command(["dart", "format", "."], "Following dart guidelines... ")
73
+
74
+ # Upgrade with major version
75
+ run_flutter_command(["flutter", "pub", "upgrade", "--major-versions"], "Upgrading major versions... ")
76
+ print(f"\n{GREEN}✓ Project cleaned successfully!{NC}")
77
+
78
+
79
+ @timer_decorator
80
+ def update_pods():
81
+ """Update iOS pods"""
82
+ if is_windows():
83
+ print(f"{YELLOW}iOS pods are not supported on Windows{NC}")
84
+ print(f"{BLUE}This command is only available on macOS and Linux{NC}")
85
+ return
86
+
87
+ # Check if ios directory exists
88
+ if not os.path.isdir("ios"):
89
+ print(f"{RED}Error: 'ios' directory not found. Are you in a Flutter project root?{NC}")
90
+ return
91
+
92
+ print(f"{YELLOW}Updating iOS pods...{NC}\n")
93
+
94
+ # Set UTF-8 encoding to prevent CocoaPods locale issues
95
+ env = os.environ.copy()
96
+ env['LANG'] = 'en_US.UTF-8'
97
+ env['LC_ALL'] = 'en_US.UTF-8'
98
+
99
+ # Navigate to iOS directory
100
+ current_dir = os.getcwd()
101
+ os.chdir("ios")
102
+ # Delete Podfile.lock
103
+ try:
104
+ os.remove("Podfile.lock")
105
+ # Use a dummy process for the loading animation
106
+ if is_windows():
107
+ run_flutter_command(["timeout", "/t", "1", "/nobreak", ">nul"], "Removing Podfile.lock ")
108
+ else:
109
+ run_flutter_command(["sleep", "0.1"], "Removing Podfile.lock ")
110
+ except FileNotFoundError:
111
+ pass
112
+ # Update pod repo (with UTF-8 env)
113
+ run_flutter_command(["pod", "repo", "update"], "Updating pod repository ", env=env)
114
+ # Install pods (with UTF-8 env)
115
+ run_flutter_command(["pod", "install"], "Installing pods ", env=env)
116
+ # Return to root directory
117
+ os.chdir(current_dir)
118
+ print(f"\n{GREEN}✓ iOS pods updated successfully!{NC}")
119
+
120
+
121
+ def create_page(page_name):
122
+ """Create page structure"""
123
+ print(f"{YELLOW}Creating page...{NC}\n")
124
+ if not page_name:
125
+ print(f"{RED}Error: Page name is required.{NC}")
126
+ print(f"Usage: {sys.argv[0]} page <page_name>")
127
+ sys.exit(1)
128
+ # Run the create_page with the page name using global path
129
+ try:
130
+ create_page_script = str(Path.home() / "scripts" / "flutter-tools" / "create_page.py")
131
+ subprocess.run([sys.executable, create_page_script, "page", page_name], check=True)
132
+ except subprocess.CalledProcessError:
133
+ print(f"{RED}Error: Failed to run page generator.{NC}")
134
+ sys.exit(1)
135
+ except FileNotFoundError:
136
+ print(f"{RED}Error: create_page.py not found.{NC}")
137
+ print(f"{YELLOW}Make sure create_page.py exists at ~/scripts/flutter-tools/{NC}")
138
+ sys.exit(1)
managers/web_deploy.py ADDED
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Web Deploy Manager - Build Flutter web and deploy to Firebase
4
+ (backend functions + frontend hosting together)
5
+ """
6
+
7
+ import subprocess
8
+
9
+ from common_utils import RED, GREEN, YELLOW, BLUE, NC, timer_decorator
10
+ from managers.build import run_flutter_command
11
+
12
+
13
+ @timer_decorator
14
+ def web_deploy():
15
+ """Build Flutter web (release) and deploy functions + hosting to Firebase."""
16
+ print(f"{YELLOW}Building Flutter web (release)...{NC}\n")
17
+
18
+ build_success = run_flutter_command(
19
+ ["flutter", "build", "web", "--release"],
20
+ "Building web... "
21
+ )
22
+
23
+ if not build_success:
24
+ print(f"\n{RED}✗ Web build failed!{NC}")
25
+ return False
26
+
27
+ print(f"\n{YELLOW}Deploying to Firebase (functions + hosting)...{NC}\n")
28
+
29
+ try:
30
+ result = subprocess.run(
31
+ ["firebase", "deploy", "--only", "functions,hosting"]
32
+ )
33
+ except FileNotFoundError:
34
+ print(f"{RED}✗ 'firebase' CLI not found.{NC}")
35
+ print(f"{YELLOW}Install it with: npm install -g firebase-tools{NC}")
36
+ return False
37
+
38
+ if result.returncode != 0:
39
+ print(f"\n{RED}✗ Firebase deploy failed!{NC}")
40
+ return False
41
+
42
+ print(f"\n{GREEN}✓ Web deployed successfully (functions + hosting)!{NC}")
43
+ return True
switch_ai.py ADDED
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ AI Service Switcher
4
+ Usage: python3 switch_ai.py [groq|mistral|sambanova|openrouter]
5
+ """
6
+
7
+ import sys
8
+ import os
9
+ import subprocess
10
+ from pathlib import Path
11
+
12
+ # Import common utilities
13
+ from common_utils import (
14
+ RED, GREEN, YELLOW, BLUE, NC, CHECKMARK, CROSS,
15
+ timer_decorator,
16
+ run_command_with_spinner,
17
+ read_env_value,
18
+ update_env_value,
19
+ get_user_shell,
20
+ is_windows
21
+ )
22
+
23
+ ENV_FILE = ".env"
24
+
25
+ def show_current_service():
26
+ """
27
+ Show current AI service and usage instructions
28
+ """
29
+ current = read_env_value("DEFAULT_AI_SERVICE")
30
+ if current:
31
+ print(f"{BLUE}📌 Current AI Service: {GREEN}{current}{NC}")
32
+ else:
33
+ print(f"{YELLOW}⚠️ DEFAULT_AI_SERVICE not found in .env{NC}")
34
+
35
+ print("")
36
+ print(f"{YELLOW}🔄 To switch service:{NC}")
37
+ print(f" {BLUE}python3 switch_ai.py groq{NC}")
38
+ print(f" {BLUE}python3 switch_ai.py mistral{NC}")
39
+ print(f" {BLUE}python3 switch_ai.py sambanova{NC}")
40
+ print(f" {BLUE}python3 switch_ai.py openrouter{NC}")
41
+
42
+ def run_setup():
43
+ """
44
+ Run the legacy installer after successful AI service switch with loading spinner
45
+ Returns:
46
+ True if successful, False otherwise
47
+ """
48
+ setup_script = Path(__file__).parent / "install_legacy.py"
49
+
50
+ if not setup_script.exists():
51
+ print(f"{YELLOW}⚠️ install_legacy.py not found, skipping setup{NC}")
52
+ return False
53
+
54
+ print("")
55
+ print(f"{YELLOW}🔧 Running install_legacy.py...{NC}")
56
+ print(f"{BLUE}{'─' * 50}{NC}")
57
+
58
+ success = run_command_with_spinner(
59
+ [sys.executable, str(setup_script)],
60
+ f"{YELLOW}Configuring environment... {NC}"
61
+ )
62
+
63
+ print(f"{BLUE}{'─' * 50}{NC}")
64
+
65
+ if success:
66
+ print(f"{GREEN}✅ Setup completed successfully!{NC}")
67
+ return True
68
+ else:
69
+ print(f"{RED}❌ Setup failed!{NC}")
70
+ return False
71
+
72
+ def reload_shell_config():
73
+ """
74
+ Reload shell configuration after successful switch
75
+ Supports zsh, bash, fish on Unix systems
76
+ """
77
+ if is_windows():
78
+ print(f"\n{YELLOW}⚠️ Windows detected - please restart your terminal{NC}")
79
+ return
80
+
81
+ print("")
82
+ print(f"{YELLOW}🔄 Reloading shell configuration...{NC}")
83
+
84
+ shell_name, config_file = get_user_shell()
85
+
86
+ try:
87
+ # Try to source the config file
88
+ subprocess.run(
89
+ [shell_name, "-c", f"source {config_file}"],
90
+ check=False,
91
+ stdout=subprocess.DEVNULL,
92
+ stderr=subprocess.DEVNULL
93
+ )
94
+ print(f"{GREEN}✅ Shell configuration reloaded!{NC}")
95
+ print("")
96
+ print(f"{BLUE}💡 If commands are not working, run manually:{NC}")
97
+ print(f" {GREEN}source {config_file}{NC}")
98
+ except Exception:
99
+ print(f"{YELLOW}⚠️ Please run manually to reload your shell:{NC}")
100
+ print(f" {GREEN}source {config_file}{NC}")
101
+
102
+ @timer_decorator
103
+ def switch_service(service):
104
+ """
105
+ Switch AI service with full validation and setup
106
+ Parameters:
107
+ service: Service name to switch to
108
+ Returns:
109
+ True if successful, False otherwise
110
+ """
111
+ # Get current service
112
+ current = read_env_value("DEFAULT_AI_SERVICE")
113
+
114
+ # Check if trying to switch to the same service
115
+ if current == service:
116
+ print(f"{YELLOW}⚠️ AI Service is already set to: {GREEN}{service}{NC}")
117
+ print(f" {BLUE}{current} → {service}{NC}")
118
+ print(f" {YELLOW}No changes made.{NC}")
119
+ return False
120
+
121
+ # Update .env file
122
+ print(f"{YELLOW}Switching AI service...{NC}\n")
123
+
124
+ if update_env_value("DEFAULT_AI_SERVICE", service):
125
+ print(f"{GREEN}✅ AI Service switched successfully!{NC}")
126
+ print(f" {BLUE}{current}{NC} → {GREEN}{service}{NC}")
127
+
128
+ # Run the legacy installer after successful switch
129
+ setup_success = run_setup()
130
+
131
+ # Reload shell configuration
132
+ reload_shell_config()
133
+
134
+ return setup_success
135
+ else:
136
+ print(f"{RED}❌ Failed to update .env file{NC}")
137
+ return False
138
+
139
+ def main():
140
+ """
141
+ Main function to handle AI service switching
142
+ """
143
+ print(f"{BLUE}{'=' * 50}{NC}")
144
+ print(f"{BLUE} AI Service Switcher{NC}")
145
+ print(f"{BLUE}{'=' * 50}{NC}\n")
146
+
147
+ # Check if .env file exists
148
+ if not os.path.exists(ENV_FILE):
149
+ print(f"{RED}❌ .env file not found!{NC}")
150
+ print(f"{YELLOW}Please create a .env file first{NC}")
151
+ sys.exit(1)
152
+
153
+ # If no argument provided, show current service
154
+ if len(sys.argv) < 2:
155
+ show_current_service()
156
+ sys.exit(0)
157
+
158
+ service = sys.argv[1].lower()
159
+
160
+ # Valid services
161
+ valid_services = ['groq', 'mistral', 'sambanova', 'openrouter']
162
+
163
+ if service not in valid_services:
164
+ print(f"{RED}❌ Invalid service: {service}{NC}")
165
+ print(f"{YELLOW} Valid options: {', '.join(valid_services)}{NC}")
166
+ sys.exit(1)
167
+
168
+ # Switch service
169
+ success = switch_service(service)
170
+
171
+ if success:
172
+ print(f"\n{GREEN}{'=' * 50}{NC}")
173
+ print(f"{GREEN}🎉 AI Service switch completed successfully!{NC}")
174
+ print(f"{GREEN}{'=' * 50}{NC}")
175
+ else:
176
+ print(f"\n{YELLOW}{'=' * 50}{NC}")
177
+ print(f"{YELLOW}⚠️ Service switch completed with warnings{NC}")
178
+ print(f"{YELLOW}{'=' * 50}{NC}")
179
+
180
+ if __name__ == "__main__":
181
+ main()