Flutter : Wings 文件结构

关于Wings

Wings 是一个基于 getx 构建的 MVC 文件结构,用于 flutter 项目。旨在减少开发时间,提高程序员的生产力。

文件结构

安装

将项目克隆到您的设备

git clone https://github.com/Invention-Technology/Flutter-Wings.git

进入项目目录并运行 flutter pub get 以安装所有依赖项。

简单使用

1- 在 features 文件夹内创建一个新文件夹,并将其命名为您的功能名称,此处我们称之为 home。

2- 创建三个名为:controller、model 和 view 的文件夹。

3- 打开 model 文件夹,创建一个名为:home.model.dart 的新文件,并在其中添加以下代码:

import 'package:wings/core/immutable/base/models/model.wings.dart';

class HomeModel implements WingsModel {
  dynamic id; // add all the properties that will be fetched from the API and will be used inside the view
  dynamic title;

  HomeModel({
    this.id,
    this.title,
  });

  @override
  List<WingsModel> fromJsonList(List<dynamic> json) {
    List<HomeModel> models = [];

    for (var element in json) {
      models.add(HomeModel.fromJson(element));
    }

    return models;
  }

  factory HomeModel.fromJson(Map<String, dynamic> json) {
      // add all the properties that you added above to assign the data that came from json to this instance
    return HomeModel(id: json['id'], title: json['title']);
  }

  @override
  WingsModel fromJson(Map<String, dynamic> json) {
    return HomeModel.fromJson(json);
  }

  @override
  Map<String, dynamic> toJson() {
      // Map the data of this instance to json object to be send to the API
    return {
      'id': id,
      'title': title,
    };
  }
}

4- 打开 controller 文件夹,创建一个名为:home.controller.dart 的新文件,并在其中添加以下代码:

import 'package:wings/core/immutable/base/controllers/controller.wings.dart';
import 'package:wings/core/immutable/providers/remote/request.wings.dart';
import 'package:wings/core/mutable/remote/urls.wings.dart';
import 'package:wings/features/index/model/index.model.dart';

class HomeController extends WingsController {
  List<HomeModel> get posts => data;

  @override
  void onInit() async {
    model = HomeModel(); // the model that coresponsidng to this feature

    request = WingsRequest(url: WingsURL.home, shouldCache: true); // request data using REST API with the option caching the response

    super.onInit();
  }
}

5- 打开 view 文件夹,创建一个名为:home.view.dart 的新文件,并在其中添加以下代码:

import 'package:flutter/material.dart';
import 'package:wings/core/immutable/base/views/view.wings.dart';

class HomeView extends WingsView<HomeController> {
  HomeView({Key? key}) : super(key: key, controller: HomeController());

  @override
  Widget successState(BuildContext context) {
    return Text(controller.posts[0].title); // Title of the first post that came from the API
  }
}

有关更多信息,请参阅 features 文件夹内提供的示例。

高级使用

主题

您可以通过进入 core/mutable/themes/theme.wings.dart 来自定义您的主题。

翻译

Wings 通过 GetX 的翻译功能支持两种默认语言:aren

  • 为每种语言添加一个新文件,名称分别为 your_file.en.dartyour_file.ar.dart

  • 您的文件应具有以下结构:

    // each key should start with the file name capitalized camel case  then : then the key capitalized camel case
    final Map<String, String> errorEn = {
      'Error:ServerException': "Oops! We couldn't connect to the server",
      'Error:CacheException': 'No Internet Connection',
    };
  • 将您刚刚添加的变量添加到文件 _en.trans.dart 中。

    import 'common.en.dart';
    import 'error.en.dart';
    import 'feedback.en.dart';
    
    // add the variable name for each file ex: errorEn with spread operator
    final Map<String, String> en = {
      ...errorEn,
      ...commonEn,
      ...feedbackEn,
    };
  • 现在您可以向您的项目添加翻译键,但不要删除现有的翻译,您可以更改翻译本身。

  • 您可以通过更改默认语言来更改默认语言。

    Wings.instance.defaultLanguage = WingsLanguage(locale: const Locale('ar'), textDirection: TextDirection.rtl);

状态

Wings 为每种用途提供了多种状态:Loading(加载)、Error(错误)、Success(成功)、ErrorFlushBar(错误提示条)、SuccessFlushBar(成功提示条),并且可以自定义每一种。

您可以在 emutable/widgets/stateemutable/helper/snack_bar 中更改每种状态的设计,并且可以添加您的自定义小部件或助手,并通过覆盖 mutable/widgets/states/app_state.wings.dart 中的默认状态。

import 'package:flutter/material.dart';

import '../../../immutable/providers/errors/error.model.wings.dart';
import '../../helpers/snack_bar/error_snack_bar.helper.wings.dart'
    as error_snack_bar;
import '../../helpers/snack_bar/success_snack_bar.helper.wings.dart'
    as success_snack_bar;
import 'error_state.widget.wings.dart';
import 'loading_state.widget.wings.dart';

class WingsAppState {
  static Widget defaultWidgetState() {
    return loading();
  }

  static Widget errorState({onRefresh, error}) {
    return WingsErrorState(
      onRefresh: onRefresh,
      error: error,
    );
  }

  static Widget loading() {
    return const LoadingState();
  }

  static void successSnackBar({String message = '', String title = ''}) {
    success_snack_bar.successSnackBar(message: message, title: title);
  }

  static void errorSnackBar({ErrorModel? error}) {
    error_snack_bar.errorSnackBar(error: error);
  }
}

远程

Wings 使用 REST API,不使用 patch 请求,因为并非所有服务器都支持 patch 请求。

您可以在 mutable/remote/urls.wings.dart 中添加您的 API URL。

class WingsURL {
  static String get baseURL => 'https://jsonplaceholder.typicode.com/';

  static String get posts => 'posts';
}

如果您有自定义响应格式,其中数据附带额外信息,您可以将您的规则添加到 mutable/remote/response_format.wings.dart 中。

import 'dart:convert';

class WingsResponseFormat {
  static String? key;

  /// This function will check if the response is valid
  /// according to the json structure that has been agreed on between
  /// the backend and the flutter developer
  ///
  /// The default wings validated response is according to JSON-API:
  /// {"data": {...}}
  ///
  /// This function require back-end api to always fill the data parameter
  /// in the json response
  ///
  /// if you don't like this json response,
  /// please change this function to always return true without checking any code
  /// static bool validatedResponse(String response) { return true; }
  static bool validatedResponse(String response) {
    return true; // TODO: uncomment this line if you don't have custom format
    try {
      key = 'data';

      var data = jsonDecode(response);

      if (data[key].toString().isEmpty) {
        return false;
      }

      return true;
    } catch (exception) {
      return false;
    }
  }
}

要发送任何请求,您必须使用 WingsRequest 类来指定请求信息:url(URL)、body(请求体)、header(请求头)、queryString(查询字符串)。

 request = WingsRequest(
  url: url,
  shouldCache: true,
  body: {
    "email":'[email protected]',
    'password':"password"
  },
);

在您的 controller 中,您可以使用 getData()sendData() 来获取/发送数据。这些方法将读取 request 变量并为您处理其余事务。

void login(){
  request = WingsRequest(
    url: WingsURL.login,
    body: {
      "email":'[email protected]',
      'password':"password"
    },
  );

  sendData();
}

您可以通过 provider 访问更多方法。您有四种方法来处理请求:provider.get(request: request)provider.insert(request: request)provider.delete(request: request)provider.update(request: request)

Statics(静态)

静态变量的目的是避免在多个地方使用字符串时出现拼写错误。

Wings 结构使用 WingsFeedbackWingsErrorAssets 作为静态变量。

自定义请求消息/资源

您可以自定义请求消息(成功和失败)以及资源。

  • 要自定义请求消息,请转到 mutable/statics/feedback.static.dart

class WingsFeedback {
  static String insertSuccess = 'Success:Insert'.tr;
}
  • 要自定义请求异常的图标和图片,请转到 mutable/statics/error_asset.static.wings.dart

class WingsErrorAssets {
    // Just in case that some icons or images deleted or not found, use those default values to handle the errors that may arise
    static String defaultImage = 'assets/images/error.png';
    static String defaultIcon = 'assets/icons/error.svg';
  
    static String unexpectedErrorImage = '';
    static String unexpectedErrorIcon = '';
      
   //................   
  }

存储

您可以存储希望在应用程序生命周期中存储和检索的数据。

class WingsStore {
  // add your data
}

助手

项目中常用的所有辅助函数,并且它们具有依赖任务,都可以移到此处。

小部件

项目中常用的所有小部件,并且它们具有依赖任务,都可以移到此处。

状态

Wings 使用 mutable/widgets/states 中的小部件,因为它们在整个结构中被广泛使用,并且可以由开发人员自定义。


Invention Technology 开发

GitHub

查看 Github