1. Anuncie Aqui ! Entre em contato fdantas@4each.com.br

[Flutter] Integrating Supabase Authentication and PowerSync Chat into Existing Flutter App...

Discussão em 'Mobile' iniciado por Stack, Setembro 11, 2024.

  1. Stack

    Stack Membro Participativo

    I'm working on a university project that involves integrating two Flutter applications. My aim is to integrate the chat and authorization functionality from the first application into the second one.


    1. I've built a chat application in Flutter using Supabase and Powersync, following this tutorial. I've also implemented Authorization with RLS (Row-Level Security).


    2. I have a second Flutter application with multiple components and various functions. However, it lacks authorization and chat functionality, which are now required features. The repository for this application can be found here.


    3. I've updated everything in the target application to which I'm transferring the chat with authorization, and I've moved most of the necessary files from the chat application with authorization to the target application.


    4. Then, I wanted to modify the main.dart file of the target application so that it displays a registration/login window first, and then redirects to the main application after successful authentication.
    Approach:


    I started by attempting to merge the main.dart files from both applications. The plan was to:

    1. Incorporate the SplashPage from the chat application as the initial screen.
    2. Use this SplashPage to check for user authentication.
    3. If not authenticated, display the registration/login window.
    4. After successful authentication, navigate to the main application interface.
    Challenges Faced:


    Despite these attempts, the application gets stuck on the loading screen. It launches and shows the initial logo, but doesn't progress to the login/registration screen or the main application interface.

    The application initializes and displays the SplashPage, but fails to navigate to the registration screen despite detecting no active session, likely due to a conflict between GoRouter and direct navigation methods.

    Relevant Code:

    Main.dart from the chat application with authorization:


    import 'package:flutter/material.dart';
    import './utils/constants.dart';
    import './pages/splash_page.dart';
    import './powersync.dart';
    import 'package:logging/logging.dart';

    import 'package:flutter_bloc/flutter_bloc.dart';
    import '../cubits/profiles/profiles_cubit.dart';

    final log = Logger('powersync-supabase');

    Future<void> main() async {
    Logger.root.level = Level.INFO;
    Logger.root.onRecord.listen((record) {
    print(
    '[${record.loggerName}] ${record.level.name}: ${record.time}: ${record.message}');

    if (record.error != null) {
    print(record.error);
    }
    if (record.stackTrace != null) {
    print(record.stackTrace);
    }
    });

    WidgetsFlutterBinding.ensureInitialized();

    await openDatabase();

    //Some example code showing printf() style debugging
    final testResults = await db.getAll('SELECT * from messages');
    log.info('testResults = $testResults');

    runApp(const MyApp());
    }

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

    @override
    Widget build(BuildContext context) {
    return BlocProvider<ProfilesCubit>(
    create: (context) => ProfilesCubit(),
    child: MaterialApp(
    title: 'SupaChat',
    debugShowCheckedModeBanner: false,
    theme: appTheme,
    home: const SplashPage(),
    ),
    );
    }
    }

    Main.dart from the target application:


    import 'package:flutter/material.dart';
    import 'package:flutter_gen/gen_l10n/app_localizations.dart';
    import 'package:go_router/go_router.dart';
    import 'package:nepanikar/app/generated/fonts.gen.dart';
    import 'package:nepanikar/app/theme/dark_theme.dart';
    import 'package:nepanikar/app/theme/theme.dart';
    import 'package:nepanikar/helpers/localization_helpers.dart';
    import 'package:nepanikar/providers/mood_chart_filter_provider.dart';
    import 'package:nepanikar/providers/mood_heatmap_filter_provider.dart';
    import 'package:nepanikar/providers/mood_state_provider.dart';
    import 'package:nepanikar/services/db/my_records/emotions_dao.dart';
    import 'package:nepanikar/services/db/my_records/mood_track_dao.dart';
    import 'package:nepanikar/services/db/user_settings/user_settings_dao.dart';
    import 'package:nepanikar/utils/app_setup.dart';
    import 'package:nepanikar/utils/registry.dart';
    import 'package:nepanikar/widgets/nepanikar_scroll_behavior.dart';
    import 'package:nepanikar_contacts_gen/nepanikar_contacts_gen.dart';
    import 'package:provider/provider.dart';

    Future<void> main() async {
    WidgetsFlutterBinding.ensureInitialized();
    await setup();
    runApp(const Nepanikar());
    }

    class Nepanikar extends StatelessWidget {



    const Nepanikar({super.key});

    GoRouter get _goRouter => registry.get<GoRouter>();

    UserSettingsDao get _userSettingsDao => registry.get<UserSettingsDao>();
    EmotionsDao get _emotionsDao => registry.get<EmotionsDao>();
    MoodTrackDao get _trackDao => registry.get<MoodTrackDao>();

    @override
    Widget build(BuildContext context) {


    return MultiProvider(
    providers: [
    ChangeNotifierProvider<MoodChartFilterProvider>(create: (_) => MoodChartFilterProvider()),
    ChangeNotifierProvider<MoodState>(create: (_) => MoodState(_emotionsDao, _trackDao)),
    ChangeNotifierProvider<MoodHeatmapFilterProvider>(create: (_) => MoodHeatmapFilterProvider()),
    ],
    child: StreamBuilder<Locale>(
    stream: _userSettingsDao.localeStream,
    builder: (_, snapshot) {
    final locale = snapshot.data;
    return StreamBuilder<ThemeMode>(
    stream: _userSettingsDao.themeModeStream,
    builder: (context, snapshot){
    final themeMode = snapshot.data ?? ThemeMode.system;
    return MaterialApp.router(
    debugShowCheckedModeBanner: false,
    title: _getAppNameFromLocale(locale),
    theme: NepanikarTheme.getThemeData(
    fontFamily: locale?.languageCode == NepanikarLanguages.uk.languageCode
    ? null
    : FontFamily.satoshi,
    ),
    darkTheme: darkTheme.getThemeData(
    fontFamily: locale?.languageCode == NepanikarLanguages.uk.languageCode
    ? null
    : FontFamily.satoshi,
    ),
    themeMode: themeMode,
    localizationsDelegates: AppLocalizations.localizationsDelegates,
    supportedLocales: AppLocalizations.supportedLocales,
    locale: locale,
    routerConfig: _goRouter,
    builder: (context, child) {
    return child != null
    ? ScrollConfiguration(
    behavior: NepanikarScrollBehavior(),
    child: MediaQuery(
    // To not influence app's font size by the system font size.
    // TODO: Should be resolved, accessibility is important.
    data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
    child: child,
    ),
    )
    : const SizedBox.shrink();
    },
    );
    },
    );
    },
    ),
    );
    }
    }

    String _getAppNameFromLocale(Locale? locale) {
    final appLangCode = locale?.languageCode ?? platformLocale;

    if (appLangCode == NepanikarLanguages.cs.languageCode) {
    return 'Nepanikař';
    } else if (appLangCode == NepanikarLanguages.sk.languageCode) {
    return 'Nepanikár';
    }
    return "Don't panic";
    }

    SplashPage.dart:


    import 'package:flutter/material.dart';
    import '../pages/register_page.dart';
    import '../pages/rooms_page.dart';
    import 'package:nepanikar/utils/constants.dart';
    import 'package:supabase_flutter/supabase_flutter.dart';
    import 'package:logging/logging.dart';

    final log = Logger('SplashPage');

    class SplashPage extends StatefulWidget {
    const SplashPage({Key? key}) : super(key: key);

    @override
    SplashPageState createState() => SplashPageState();
    }

    class SplashPageState extends State<SplashPage> {
    @override
    void initState() {
    super.initState();
    log.info('SplashPage initialized');
    getInitialSession();
    }

    Future<void> getInitialSession() async {
    log.info('Starting getInitialSession');
    await Future.delayed(Duration.zero);

    try {
    final session = supabase.auth.currentSession;
    log.info('Current session: ${session != null ? 'exists' : 'null'}');

    if (!mounted) return;

    if (session == null) {
    log.info('No session, navigating to register page');
    await Navigator.of(context).pushReplacement(
    MaterialPageRoute(
    builder: (_) => const RegisterPage(isRegistering: true),
    ),
    );
    } else {
    log.info('Session exists, navigating to rooms page');
    await Navigator.of(context).pushReplacement(
    MaterialPageRoute(builder: (_) => const RoomsPage()),
    );
    }
    } catch (error) {
    log.severe('Error during session check: $error');
    if (!mounted) return;
    ScaffoldMessenger.of(context).showSnackBar(
    const SnackBar(content: Text('Error occurred during session refresh')),
    );
    await Navigator.of(context).pushReplacement(
    MaterialPageRoute(
    builder: (_) => const RegisterPage(isRegistering: true),
    ),
    );
    }
    }

    @override
    Widget build(BuildContext context) {
    log.info('Building SplashPage');
    return const Scaffold(
    body: Center(child: CircularProgressIndicator()),
    );
    }
    }

    Question:


    How can I effectively integrate the authentication and chat functionality from the first application into the second one, ensuring that the application first checks for authentication and displays the login/register screen when necessary, before proceeding to the main application?

    Any guidance on the best approach to merge these functionalities while maintaining the existing features of the target application would be greatly appreciated.

    Continue reading...

Compartilhe esta Página