zipy_flutter 0.1.0 copy "zipy_flutter: ^0.1.0" to clipboard
zipy_flutter: ^0.1.0 copied to clipboard

Release of the zipy_flutter package, compatible with both iOS and Android.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:zipy_flutter/zipy_flutter.dart';
import 'package:zipy_flutter_example/screens/login_screen.dart';
import 'package:zipy_flutter_example/screens/misc_screen_4.dart';
import 'package:zipy_flutter_example/screens/misc_screen_5.dart';
import 'screens/home_screen.dart';
import 'screens/api_call_screen.dart';
import 'screens/misc_screen_1.dart';
import 'screens/misc_screen_2.dart';
import 'screens/misc_screen_3.dart';
import 'screens/error_simulation_screen.dart';
import 'screens/anr_crash_screen.dart';
import 'errors/error_screen.dart';
import 'api/graphql_api.dart'; // Import the file where `setupGraphQLClient` is defined

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  setupGraphQLClient();
  runApp(const ZipyWrapper(child: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  static var apikey = "";

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Custom Flutter App',
      theme: ThemeData(primarySwatch: Colors.blue),
      navigatorObservers: [ZipyNavigationObserver()],
      initialRoute: '/ask-apikey',
      routes: {
        '/ask-apikey': (context) => const ApiKeyScreen(),
        '/login': (context) => const LoginScreen(),
        '/home': (context) => const HomeScreen(),
        '/api-calls': (context) => const ApiCallScreen(),
        '/misc-1': (context) => const MiscScreen1(),
        '/misc-2': (context) => const MiscScreen2(),
        '/misc-3': (context) => const MiscScreen3(),
        '/misc-4': (context) => const MiscScreen4(),
        '/misc-5': (context) => const MiscScreen5(),
        '/error-simulation': (context) => const ErrorSimulationScreen(),
        '/anr-crash': (context) => const AnrCrashScreen(),
        '/zipy-logs': (context) => const ErrorScreen(),
      },
      // Wrap the child with a Stack so we can add a persistent header.
      builder: (context, child) {
        return Builder(
          builder: (context) {
            // Show API key dialog only if apikey is empty

            final bool isKeyboardVisible =
                MediaQuery.of(context).viewInsets.bottom > 0;

            return Scaffold(
              body: Stack(
                children: [
                  child ?? Container(),
                  // Bottom bar with buttons
                  if (!isKeyboardVisible) // Hide when keyboard is visible
                    Positioned(
                      bottom: 0,
                      left: 0,
                      right: 0,
                      child: Container(
                        decoration: BoxDecoration(
                          color: Colors.white,
                          boxShadow: [
                            BoxShadow(
                              color: Colors.black.withOpacity(0.1),
                              blurRadius: 8,
                              offset: const Offset(0, -2),
                            ),
                          ],
                        ),
                        padding: EdgeInsets.only(
                          left: 12,
                          right: 12,
                          bottom: MediaQuery.of(context).padding.bottom + 4,
                          top: 4,
                        ),
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            // Buttons Row
                            Row(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                              children: [
                                _buildActionButton(
                                  onPressed: () {
                                    print('apiKey: $apikey');
                                    Zipy.init(key: apikey);
                                  },
                                  label: 'Initialize',
                                  icon: Icons.play_arrow_rounded,
                                ),
                                _buildActionButton(
                                  onPressed: () {
                                    Zipy.pause();
                                  },
                                  label: 'Pause',
                                  icon: Icons.pause_rounded,
                                ),
                                _buildActionButton(
                                  onPressed: () {
                                    Zipy.resume();
                                  },
                                  label: 'Resume',
                                  icon: Icons.refresh_rounded,
                                ),
                                _buildActionButton(
                                  onPressed: () {
                                    Zipy.stop();
                                  },
                                  label: 'Stop',
                                  icon: Icons.stop_rounded,
                                ),
                              ],
                            ),
                            const SizedBox(height: 4),
                            // Session Controls Text at bottom
                            Container(
                              padding: const EdgeInsets.symmetric(
                                horizontal: 8,
                                vertical: 2,
                              ),
                              decoration: BoxDecoration(
                                color: Colors.blue.withOpacity(0.1),
                                borderRadius: BorderRadius.circular(8),
                              ),
                              child: const Row(
                                mainAxisSize: MainAxisSize.min,
                                children: [
                                  Icon(
                                    Icons.settings_outlined,
                                    size: 12,
                                    color: Colors.blue,
                                  ),
                                  SizedBox(width: 4),
                                  Text(
                                    'Session Controls',
                                    style: TextStyle(
                                      fontSize: 10,
                                      fontWeight: FontWeight.w500,
                                      color: Colors.blue,
                                      letterSpacing: 0.5,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                ],
              ),
            );
          },
        );
      },
    );
  }
}

Widget _buildActionButton({
  required VoidCallback onPressed,
  required String label,
  required IconData icon,
}) {
  return SizedBox(
    width: 65, // Reduced width
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Container(
          decoration: BoxDecoration(
            color: Colors.blue.withOpacity(0.1),
            borderRadius: BorderRadius.circular(8),
          ),
          child: Material(
            color: Colors.transparent,
            child: InkWell(
              onTap: onPressed,
              borderRadius: BorderRadius.circular(8),
              child: Padding(
                padding: const EdgeInsets.all(6.0),
                child: Icon(
                  icon,
                  color: Colors.blue,
                  size: 20, // Smaller icon
                ),
              ),
            ),
          ),
        ),
        const SizedBox(height: 2),
        Text(
          label,
          style: const TextStyle(
            fontSize: 10, // Smaller text
            color: Colors.black54,
            fontWeight: FontWeight.w500,
          ),
          textAlign: TextAlign.center,
        ),
      ],
    ),
  );
}

class ApiKeyScreen extends StatelessWidget {
  const ApiKeyScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: SingleChildScrollView(
          child: Container(
            width: MediaQuery.of(context).size.width > 450
                ? 400
                : MediaQuery.of(context).size.width * 0.9,
            padding: const EdgeInsets.all(24),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Container(
                  padding: const EdgeInsets.all(16),
                  decoration: BoxDecoration(
                    color: Colors.blue.withOpacity(0.1),
                    shape: BoxShape.circle,
                  ),
                  child: const Icon(
                    Icons.vpn_key_rounded,
                    size: 48,
                    color: Colors.blue,
                  ),
                ),
                const SizedBox(height: 24),
                const Text(
                  'Welcome to Zipy Sample App',
                  style: TextStyle(
                    fontSize: 28,
                    fontWeight: FontWeight.bold,
                    color: Colors.black87,
                  ),
                  textAlign: TextAlign.center,
                ),
                const SizedBox(height: 12),
                const Text(
                  'Please enter your API key to continue',
                  style: TextStyle(
                    fontSize: 16,
                    color: Colors.black54,
                  ),
                  textAlign: TextAlign.center,
                ),
                const SizedBox(height: 32),
                _ApiKeyForm(),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class _ApiKeyForm extends StatefulWidget {
  @override
  State<_ApiKeyForm> createState() => _ApiKeyFormState();
}

class _ApiKeyFormState extends State<_ApiKeyForm> {
  final TextEditingController controller = TextEditingController();
  bool isHovered = false;
  bool isInputFocused = false;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Focus(
          onFocusChange: (hasFocus) {
            setState(() {
              isInputFocused = hasFocus;
            });
          },
          child: TextField(
            controller: controller,
            onChanged: (value) {
              setState(() {});
            },
            decoration: InputDecoration(
              hintText: 'Enter your API key',
              hintStyle: TextStyle(color: Colors.grey[400]),
              filled: true,
              fillColor: Colors.grey[50],
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(16),
                borderSide: BorderSide.none,
              ),
              focusedBorder: OutlineInputBorder(
                borderRadius: BorderRadius.circular(16),
                borderSide: const BorderSide(color: Colors.blue, width: 2),
              ),
              prefixIcon: const Icon(
                Icons.key_outlined,
                color: Colors.blue,
              ),
              contentPadding: const EdgeInsets.symmetric(
                horizontal: 24,
                vertical: 20,
              ),
            ),
          ),
        ),
        const SizedBox(height: 32),
        MouseRegion(
          onEnter: (_) => setState(() => isHovered = true),
          onExit: (_) => setState(() => isHovered = false),
          child: AnimatedContainer(
            duration: const Duration(milliseconds: 200),
            transform: Matrix4.identity()..scale(isHovered ? 1.02 : 1.0),
            child: ElevatedButton(
              onPressed: controller.text.isEmpty
                  ? null
                  : () {
                      MyApp.apikey = controller.text;
                      Navigator.of(context).pushReplacementNamed('/login');
                    },
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.blue,
                foregroundColor: Colors.white,
                padding: const EdgeInsets.symmetric(
                  horizontal: 48,
                  vertical: 20,
                ),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(16),
                ),
                elevation: isHovered ? 8 : 4,
              ),
              child: const Text(
                'Continue to Login',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
        ),
      ],
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

class ApiKeyLoginScreen extends StatelessWidget {
  const ApiKeyLoginScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return const LoginScreen();
  }
}
1
likes
0
points
1.49k
downloads

Publisher

unverified uploader

Weekly Downloads

Release of the zipy_flutter package, compatible with both iOS and Android.

Homepage
Repository (GitHub)
View/report issues

Documentation

Documentation

License

unknown (license)

Dependencies

dio, fixnum, flutter, http, path, path_provider, plugin_platform_interface, protobuf

More

Packages that depend on zipy_flutter