#!/usr/bin/env python3 """ OverCode Progress Bars - Epic animated progress indicators """ import time import sys import threading from colorama import Fore, Style, init init(autoreset=True) class ProgressBar: """Animated progress bar with multiple styles""" def __init__(self, total=100, width=40, style='modern', color='cyan'): self.total = total self.current = 0 self.width = width self.style = style self.color = color self.start_time = time.time() self.is_running = False self.animation_thread = None # Color mapping self.colors = { 'cyan': Fore.CYAN, 'green': Fore.GREEN, 'yellow': Fore.YELLOW, 'red': Fore.RED, 'magenta': Fore.MAGENTA, 'blue': Fore.BLUE } # Style configurations self.styles = { 'modern': { 'filled': '█', 'empty': '░', 'prefix': '[', 'suffix': ']' }, 'classic': { 'filled': '=', 'empty': '-', 'prefix': '[', 'suffix': ']' }, 'dots': { 'filled': '●', 'empty': '○', 'prefix': '(', 'suffix': ')' }, 'arrows': { 'filled': '▶', 'empty': '▷', 'prefix': '⟨', 'suffix': '⟩' }, 'blocks': { 'filled': '■', 'empty': '□', 'prefix': '⌊', 'suffix': '⌋' }, 'fire': { 'filled': '🔥', 'empty': '💨', 'prefix': '🚀', 'suffix': '✨' } } def update(self, value, message=""): """Update progress bar value""" self.current = min(value, self.total) self._render(message) def increment(self, amount=1, message=""): """Increment progress by amount""" self.current = min(self.current + amount, self.total) self._render(message) def _render(self, message=""): """Render the progress bar""" if self.total == 0: percentage = 100 else: percentage = (self.current / self.total) * 100 filled_width = int((self.current / self.total) * self.width) if self.total > 0 else 0 empty_width = self.width - filled_width style_config = self.styles.get(self.style, self.styles['modern']) color = self.colors.get(self.color, Fore.CYAN) # Build progress bar filled = style_config['filled'] * filled_width empty = style_config['empty'] * empty_width prefix = style_config['prefix'] suffix = style_config['suffix'] # Calculate ETA elapsed = time.time() - self.start_time if self.current > 0: eta = (elapsed / self.current) * (self.total - self.current) eta_str = f" ETA: {eta:.1f}s" else: eta_str = "" # Format the bar bar = f"{color}{prefix}{filled}{Fore.LIGHTBLACK_EX}{empty}{color}{suffix}" percentage_str = f" {percentage:6.1f}%" if message: message = f" {Fore.WHITE}{message}" # Print with carriage return to overwrite sys.stdout.write(f"\r{bar}{percentage_str}{eta_str}{message}") sys.stdout.flush() if self.current >= self.total: print() # New line when complete class SpinnerProgress: """Animated spinner for indefinite operations""" def __init__(self, message="Loading", style='dots'): self.message = message self.style = style self.is_running = False self.thread = None self.spinners = { 'dots': ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'], 'arrows': ['←', '↖', '↑', '↗', '→', '↘', '↓', '↙'], 'bars': ['|', '/', '-', '\\'], 'blocks': ['▁', '▃', '▄', '▅', '▆', '▇', '█', '▇', '▆', '▅', '▄', '▃'], 'braille': ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'], 'fire': ['🔥', '🚀', '⚡', '✨', '💫', '🌟'] } def start(self): """Start the spinner animation""" if self.is_running: return self.is_running = True self.thread = threading.Thread(target=self._animate) self.thread.daemon = True self.thread.start() def stop(self, final_message="Done"): """Stop the spinner""" self.is_running = False if self.thread: self.thread.join() # Clear the line and show final message sys.stdout.write(f"\r{Fore.GREEN}✓ {final_message}{' ' * 20}\n") sys.stdout.flush() def _animate(self): """Animation loop""" frames = self.spinners.get(self.style, self.spinners['dots']) i = 0 while self.is_running: frame = frames[i % len(frames)] sys.stdout.write(f"\r{Fore.CYAN}{frame} {Fore.WHITE}{self.message}") sys.stdout.flush() time.sleep(0.1) i += 1 class MultiProgress: """Multiple progress bars for complex operations""" def __init__(self): self.bars = {} self.order = [] def add_bar(self, name, total, style='modern', color='cyan'): """Add a new progress bar""" self.bars[name] = { 'bar': ProgressBar(total, style=style, color=color), 'total': total, 'current': 0, 'message': '' } self.order.append(name) def update(self, name, value, message=""): """Update a specific progress bar""" if name in self.bars: self.bars[name]['current'] = value self.bars[name]['message'] = message self._render_all() def increment(self, name, amount=1, message=""): """Increment a specific progress bar""" if name in self.bars: self.bars[name]['current'] = min( self.bars[name]['current'] + amount, self.bars[name]['total'] ) self.bars[name]['message'] = message self._render_all() def _render_all(self): """Render all progress bars""" # Move cursor up to overwrite previous output if len(self.bars) > 1: sys.stdout.write(f"\033[{len(self.bars)}A") for name in self.order: bar_data = self.bars[name] bar_data['bar'].current = bar_data['current'] print(f"{Fore.YELLOW}{name:<15}", end=" ") bar_data['bar']._render(bar_data['message']) # Utility functions for easy use def progress_bar(iterable, desc="Processing", style='modern', color='cyan'): """Wrapper for iterables with progress bar""" total = len(iterable) if hasattr(iterable, '__len__') else 100 bar = ProgressBar(total, style=style, color=color) for i, item in enumerate(iterable): bar.update(i + 1, desc) yield item bar.update(total, f"{desc} - Complete!") def simulate_progress(message="Processing", duration=3, style='modern', color='cyan'): """Simulate progress for demo purposes""" bar = ProgressBar(100, style=style, color=color) for i in range(101): time.sleep(duration / 100) bar.update(i, message) def with_spinner(func, message="Loading", style='dots'): """Decorator to show spinner during function execution""" def wrapper(*args, **kwargs): spinner = SpinnerProgress(message, style) spinner.start() try: result = func(*args, **kwargs) spinner.stop("Complete!") return result except Exception as e: spinner.stop(f"Error: {str(e)}") raise return wrapper # Demo functions def demo_progress_bars(): """Demonstrate different progress bar styles""" print(Fore.CYAN + "🚀 OverCode Progress Bar Demo") print("=" * 50) styles = ['modern', 'classic', 'dots', 'arrows', 'blocks', 'fire'] colors = ['cyan', 'green', 'yellow', 'magenta', 'blue'] for style in styles: color = colors[styles.index(style) % len(colors)] print(f"\n{Fore.WHITE}Style: {style.title()} ({color})") bar = ProgressBar(50, style=style, color=color) for i in range(51): bar.update(i, f"Processing {style} style...") time.sleep(0.02) print(f"\n{Fore.GREEN}✨ All styles demonstrated!") def demo_spinner(): """Demonstrate spinner animations""" print(Fore.CYAN + "\n🔄 Spinner Demo") styles = ['dots', 'arrows', 'bars', 'blocks', 'braille', 'fire'] for style in styles: spinner = SpinnerProgress(f"Loading with {style} style", style) spinner.start() time.sleep(2) spinner.stop(f"{style.title()} complete!") def demo_multi_progress(): """Demonstrate multiple progress bars""" print(Fore.CYAN + "\n📊 Multi-Progress Demo") multi = MultiProgress() multi.add_bar("Download", 100, 'modern', 'green') multi.add_bar("Extract", 80, 'arrows', 'yellow') multi.add_bar("Install", 60, 'dots', 'blue') import random for i in range(100): if i < 80: multi.increment("Download", 1, f"Downloading file {i+1}") if i > 20 and i < 60: multi.increment("Extract", random.randint(1, 2), "Extracting files...") if i > 40: multi.increment("Install", 1, "Installing packages...") time.sleep(0.05) print(f"\n{Fore.GREEN}🎉 All operations complete!") if __name__ == "__main__": demo_progress_bars() demo_spinner() demo_multi_progress()