flutter_kore 1.6.1 copy "flutter_kore: ^1.6.1" to clipboard
flutter_kore: ^1.6.1 copied to clipboard

This library contains components for Flutter architecture, and also utility classes for HTTP, navigation and DI

example/lib/main.dart

import 'package:dart_mappable/dart_mappable.dart';
import 'package:dio/dio.dart' as dio;
import 'package:flutter/foundation.dart';
import 'package:material_ui/material_ui.dart';
import 'package:flutter_kore/flutter_kore.dart';
import 'package:flutter_kore/flutter_kore_widgets.dart';

part 'main.api.dart';
part 'main.kore.dart';
part 'main.mapper.dart';

class const PostLikedEvent({required final int id});

@MappableClass()
class const Post({
  required final String? title,
  required final String? body,
  required final int? id,
  final bool isLiked = false,
}) with PostMappable {
  static const fromMap = PostMapper.fromMap;
}

@MappableClass()
class const PostsState({
  final StatefulData<List<Post>>? posts,
  final bool? active,
}) with PostsStateMappable;

@mainApi
class Apis with ApisGen {}

@mainApp
class App extends KoreApp with AppGen {
  final apis = Apis();

  @override
  Future<void> initialize() async {
    await super.initialize();
  }
}

final app = App();

Future<void> main() async {
  await app.initialize();

  runApp(
    const MaterialApp(debugShowCheckedModeBanner: false, home: PostsListView()),
  );
}

class HttpRequest<T> extends DioRequest<T> {
  @override
  RequestSettings<dio.Interceptor> get defaultSettings => RequestSettings(
    logPrint: (message) {
      if (kDebugMode) {
        print(message);
      }
    },
    exceptionPrint: (error, trace) {
      if (kDebugMode) {
        print(error);
        print(trace);
      }
    },
  );

  @override
  void decorateRequest(dio.Dio dio, dio.Options options) {
    // ignore
  }

  @override
  Future onError(dio.DioException error, RetryHandler retry) async {
    return error;
  }
}

@api
class PostsApi {
  HttpRequest<List<Post>> getPosts(int offset, int limit) =>
      HttpRequest<List<Post>>()
        ..method = .get
        ..baseUrl = 'http://jsonplaceholder.typicode.com'
        ..url = '/posts'
        ..parser = (result, headers) async {
          final list = <Post>[];

          result?.forEach((data) {
            list.add(Post.fromMap(data));
          });

          return list;
        };
}

@basicInstance
class PostsInteractor
    extends BaseInteractor<PostsState, Map<String, dynamic>?> {
  Future<void> loadPosts(int offset, int limit, {bool refresh = false}) async {
    updateState(state.copyWith(posts: const LoadingData()));

    late Response<List<Post>> response;

    if (refresh) {
      response = await executeAndCancelOnDispose(
        app.apis.posts.getPosts(0, limit),
      );
    } else {
      response = await executeAndCancelOnDispose(
        app.apis.posts.getPosts(offset, limit),
      );
    }

    if (response.isSuccessful) {
      updateState(
        state.copyWith(posts: SuccessData(result: response.result ?? [])),
      );
    } else {
      updateState(state.copyWith(posts: ErrorData(error: response.error)));
    }
  }

  @override
  void subscribe() {
    on<PostLikedEvent>((event) {
      // update state
    });
  }

  @override
  PostsState get initialState => const PostsState();
}

class const PostsListView({super.key, super.viewModel}) extends BaseWidget {
  @override
  State<StatefulWidget> createState() {
    return _PostsListViewWidgetState();
  }
}

class _PostsListViewWidgetState extends BaseIndependentView<PostsListView> {
  @override
  DependentKoreInstanceConfiguration get configuration =>
      DependentKoreInstanceConfiguration(
        dependencies: [app.connectors.postsInteractorConnector()],
      );

  late final postsInteractor = useLocalInstance<PostsInteractor>();

  late final posts = postsInteractor.wrapUpdates((state) => state.posts);

  void openPost(Post post) {
    // app.navigation.routeTo(
    //   app.navigation.routes.post(
    //     post: post,
    //   ),
    //   forceGlobal: true,
    // );
  }

  void like(int id) {
    app.eventBus.send(PostLikedEvent(id: id));
  }

  @override
  void initState() {
    super.initState();

    postsInteractor.loadPosts(0, 30, refresh: true);
  }

  @override
  Widget buildView(BuildContext context) {
    return Scaffold(
      backgroundColor: const .fromARGB(255, 232, 232, 232),
      appBar: AppBar(title: const Text('Posts')),
      body: KoreStreamBuilder(
        streamWrap: posts,
        builder: (context, snapshot) {
          if (snapshot.hasData && snapshot.data != null) {
            return buildList(snapshot.data!);
          }

          return Container();
        },
      ),
    );
  }

  Widget buildList(StatefulData<List<Post>> data) {
    switch (data) {
      case LoadingData():
        return const Center(child: CircularProgressIndicator());
      case SuccessData<List<Post>>(:final result):
        return ListView.builder(
          itemBuilder: (context, index) {
            final item = result[index];

            return PostCard(
              onTap: () {
                openPost(item);
              },
              onLikeTap: () {
                like(item.id ?? 1);
              },
              title: item.title ?? '',
              body: item.body ?? '',
              isLiked: item.isLiked,
            );
          },
          itemCount: result.length,
        );
      case ErrorData<List<Post>>(:final error):
        return Text(error.toString());
    }
  }
}

class const PostCard({
  super.key,
  required final VoidCallback onTap,
  required final String title,
  required final String body,
  required final bool isLiked,
  required final VoidCallback onLikeTap,
}) extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTap,
      child: Card(
        elevation: 0,
        margin: const .symmetric(horizontal: 16, vertical: 12),
        child: Padding(
          padding: const .symmetric(horizontal: 16, vertical: 12),
          child: Column(
            crossAxisAlignment: .start,
            spacing: 8,
            children: [
              _buildUserHeader(),
              Text(title, style: const TextStyle(fontSize: 20)),
              Text(body),
              _buildControls(),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildControls() => Row(
    mainAxisAlignment: .end,
    children: [
      GestureDetector(
        onTap: onLikeTap,
        child: Icon(
          Icons.heart_broken,
          color: isLiked ? Colors.red : Colors.grey,
        ),
      ),
    ],
  );

  Widget _buildUserHeader() => const Row(
    children: [
      Icon(Icons.person),
      Text('Unnamed user', style: TextStyle(fontWeight: FontWeight.bold)),
    ],
  );
}
2
likes
160
points
256
downloads

Documentation

Documentation
API reference

Publisher

verified publisherredcollar.co

Weekly Downloads

This library contains components for Flutter architecture, and also utility classes for HTTP, navigation and DI

Repository (GitHub)
View/report issues

Topics

#state-management #di #navigation #http

License

MIT (license)

Dependencies

async, cupertino_ui, dio, flutter, material_ui, universal_platform, visibility_detector

More

Packages that depend on flutter_kore