1656756000
A Flutter plugin to show incoming call in your Flutter app! Alpha version(not ready for production!)
To use this plugin:
<activity
android:name="com.github.alezhka.flutter_incoming_call.IncomingCallActivity"
android:theme="@style/Theme.AppCompat"
android:screenOrientation="portrait"
android:showOnLockScreen="true">
<intent-filter>
<action android:name="com.github.alezhka.flutter_incoming_call.activity.ACTION_INCOMING_CALL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<receiver android:name="com.github.alezhka.flutter_incoming_call.CallBroadcastReceiver"
android:enabled="true"
android:exported="false"/>
FlutterIncomingCall.configure(
appName: 'example_incoming_call',
duration: 30000,
android: ConfigAndroid(
vibration: true,
ringtonePath: 'default',
channelId: 'calls',
channelName: 'Calls channel name',
channelDescription: 'Calls channel description',
),
ios: ConfigIOS(
iconName: 'AppIcon40x40',
ringtonePath: null,
includesCallsInRecents: false,
supportsVideo: true,
maximumCallGroups: 2,
maximumCallsPerCallGroup: 1,
)
)
FlutterIncomingCall.onEvent.listen((event) {
if(event is CallEvent) { // Android | IOS
} else if(event is HoldEvent) { // IOS
} else if(event is MuteEvent) { // IOS
} else if(event is DmtfEvent) { // IOS
} else if(event is AudioSessionEvent) { // IOS
}
});
FlutterIncomingCall.displayIncomingCall(String uid, String name, String avatar, String handle, String type, bool isVideo);
FlutterIncomingCall.endCall(String uuid);
FlutterIncomingCall.endAllCalls();
ios | ios (Lockscreen) | Android | Android (Lockscreen) |
---|---|---|---|
![]() | ![]() |
Check out the example in the example project folder for a working example.
Run this command:
With Flutter:
$ flutter pub add flutter_incoming_call
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
flutter_incoming_call: ^0.1.1
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:flutter_incoming_call/flutter_incoming_call.dart';
example/lib/main.dart
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter_incoming_call/flutter_incoming_call.dart';
import 'package:uuid/uuid.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var uuid = Uuid();
BaseCallEvent? _lastEvent;
CallEvent? _lastCallEvent;
HoldEvent? _lastHoldEvent;
MuteEvent? _lastMuteEvent;
DmtfEvent? _lastDmtfEvent;
AudioSessionEvent? _lastAudioSessionEvent;
void _incomingCall() {
final uid = uuid.v4();
final name = 'Daenerys Targaryen';
final avatar = 'https://scontent.fhel6-1.fna.fbcdn.net/v/t1.0-9/62009611_2487704877929752_6506356917743386624_n.jpg?_nc_cat=102&_nc_sid=09cbfe&_nc_ohc=cIgJjOYlVj0AX_J7pnl&_nc_ht=scontent.fhel6-1.fna&oh=ef2b213b74bd6999cd74e3d5de235cf4&oe=5F6E3331';
final handle = 'example_incoming_call';
final type = HandleType.generic;
final isVideo = true;
FlutterIncomingCall.displayIncomingCall(uid, name, avatar, handle, type, isVideo);
}
void _endCurrentCall() {
if(_lastEvent != null) {
FlutterIncomingCall.endCall(_lastCallEvent!.uuid);
}
}
void _endAllCalls() {
FlutterIncomingCall.endAllCalls();
}
@override
void initState() {
super.initState();
FlutterIncomingCall.configure(
appName: 'example_incoming_call',
duration: 30000,
android: ConfigAndroid(
vibration: true,
ringtonePath: 'default',
channelId: 'calls',
channelName: 'Calls channel name',
channelDescription: 'Calls channel description',
),
ios: ConfigIOS(
iconName: 'AppIcon40x40',
ringtonePath: null,
includesCallsInRecents: false,
supportsVideo: true,
maximumCallGroups: 2,
maximumCallsPerCallGroup: 1,
)
);
FlutterIncomingCall.onEvent.listen((event) {
setState(() { _lastEvent = event; });
if(event is CallEvent) {
setState(() { _lastCallEvent = event; });
} else if(event is HoldEvent) {
setState(() { _lastHoldEvent = event; });
} else if(event is MuteEvent) {
setState(() { _lastMuteEvent = event; });
} else if(event is DmtfEvent) {
setState(() { _lastDmtfEvent = event; });
} else if(event is AudioSessionEvent) {
setState(() { _lastAudioSessionEvent = event; });
}
});
}
@override
void dispose() {
_endAllCalls();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
TextButton(
child: Text('Incoming call now'),
onPressed: _incomingCall,
),
SizedBox(height: 16),
TextButton(
child: Text('Incoming call delay 5 sec'),
onPressed: () => Future.delayed(Duration(seconds: 5), _incomingCall),
),
SizedBox(height: 16),
TextButton(
child: Text('End current call'),
onPressed: _endCurrentCall,
),
SizedBox(height: 16),
TextButton(
child: Text('End all calls'),
onPressed: _endAllCalls,
),
SizedBox(height: 16),
Text(
'Last event:',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
_lastEvent != null ? _lastEvent.toString() : 'Not event',
style: TextStyle(
fontSize: 16
),
),
if(_lastCallEvent != null) ...[
Text(
'Last call event:',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
_lastCallEvent.toString(),
style: TextStyle(
fontSize: 16
),
)
],
if(_lastHoldEvent != null) ...[
Text(
'Last hold event:',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
_lastHoldEvent.toString(),
style: TextStyle(
fontSize: 16
),
)
],
if(_lastMuteEvent != null) ...[
Text(
'Last mute event:',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
_lastMuteEvent.toString(),
style: TextStyle(
fontSize: 16
),
)
],
if(_lastDmtfEvent != null) ...[
Text(
'Last dmtf event:',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
_lastDmtfEvent.toString(),
style: TextStyle(
fontSize: 16
),
)
],
if(_lastAudioSessionEvent != null) ...[
Text(
'Last audio session event:',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
_lastAudioSessionEvent.toString(),
style: TextStyle(
fontSize: 16
),
)
]
],
),
),
),
);
}
}
Author: Alezhka
Source code: https://github.com/Alezhka/flutter_incoming_call
License: GPL-3.0 license
1656756000
BidmadPlugin is a plugin for using Bidmad, a mobile app advertisement SDK, in Flutter.
You can use the plugin to serve banner/interstitial/reward ads in your flutter mobile app.
*If you are using a version lower than 1.0.0, please check here first before proceeding to the guide below.
Add the options below to gradle.properties
...
android.enableDexingArtifactTransform=false
If you are using Proguard, add the rule below.
...
-keep class com.adop.sdk.** { *; }
-keep class ad.helper.openbidding.** { *; }
-keep class com.adop.adapter.fc.** { *; }
-keep class com.adop.adapter.fnc.** { *; }
-keepnames class * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}
# Pangle
-keep class com.bytedance.sdk.** { *; }
-keep class com.bykv.vk.openvk.component.video.api.** { *; }
# Tapjoy
-keep class com.tapjoy.** { *; }
-keep class com.moat.** { *; }
-keepattributes JavascriptInterface
-keepattributes *Annotation*
-keep class * extends java.util.ListResourceBundle {
protected Object[][] getContents();
}
-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
public static final *** NULL;
}
-keepnames @com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
@com.google.android.gms.common.annotation.KeepName *;
}
-keepnames class * implements android.os.Parcelable {
public static final ** CREATOR;
}
-keep class com.google.android.gms.ads.identifier.** { *; }
-dontwarn com.tapjoy.**
After fetching our plugin into your app by "flutter pub get", a "Podfile" will be generated in your project's iOS Folder.
Select "No" for Enable Bitcode under your Build Setting.
To use AdNetworks provided by BidmadSDK, you need to add SKAdNetworkIdentifier to Info.plist. Please add SKAdNetworkItems below to info.plist.
<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>cstr6suwn9.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>v9wttpbfk9.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>n38lu8286q.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4dzt52r2t5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>bvpn9ufa9b.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>2u9pt9hc89.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4468km3ulz.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>4fzdc2evr5.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>7ug5zh24hu.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>8s468mfl3y.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>9rd848q2bz.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>9t245vhmpl.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>av6w8kgt66.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>f38h382jlk.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>hs6bdukanm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>kbd757ywx3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ludvb6z3bs.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>m8dbw4sv7c.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>mlmmfzh3r3.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>prcb7njmu6.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>t38b2kh725.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>tl55sbb4fm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>wzmmz9fp6w.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>yclnxrl5pm.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>ydx93a7ass.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>238da6jt44.skadnetwork</string>
</dict>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>22mmun2rn5.skadnetwork</string>
</dict>
</array>
Also, please add NSUserTrackingUsageDescription with your own description of why you would like to track user data (e.g. "App would like to access IDFA for tracking purpose") into info.plist
...
<key>NSUserTrackingUsageDescription</key>
<string>App would like to access IDFA for tracking purpose</string>
...
At the starting point of your app, please call initializeSdk(). If initializeSdk method is not called, SDK initializes itself on your first loading, which subsequently may delay your first ad loading.
FlutterBidmadCommon().initializeSdk();
For interstitial and rewarded ads, instead of calling initializeSdk(), load your first ad at the starting point of your app by following the interstitial and rewarded ad loading guide below, and show your ad at the point of your choice.
The following is an example of requesting a Banner ad.
3.1.1 Banner placement based on position
....//Banner init
FlutterBidmadCommon common = FlutterBidmadCommon();
FlutterBaseBanner banner;
common.initBannerChannel().then((value) {
String _channelNm = value;
banner = FlutterBaseBanner(
channelName: _channelNm
);
banner.setAdInfo("Your Zone Id");
banner.setCallbackListener(
onLoadAd: (String zoneId){
print("banner onLoadAd");
},
onFailAd: (String zoneId){
print("banner onFailAd");
}
);
//option
//banner.setInterval(120); //banner refresh time(60s~120s)
});
....//Banner Load
banner.load(300); //set Position Y(height)
....//Banner Remove
banner.removeAdView();
3.1.2 Banner Widget
....//Banner Widget init
Container(
child: BidmadBannerWidget(
onBidmadBannerWidgetCreated: _onWidgetTestCreated,
),
height: 50.0, //Banner Height(50, 100, 250)
),
....//onBidmadBannerWidgetCreated
void _onWidgetTestCreated(FlutterBaseBanner controller){
controller.setAdInfo("Your Zone Id");
controller.setCallbackListener(
onLoadAd: (String zoneId){
print("banner onLoadAd");
},
onFailAd: (String zoneId){
print("banner onFailAd");
}
);
controller.loadWidget();
}
The following is an example of requesting a Interstitial ad.
....//Interstitial init
FlutterBidmadCommon common = FlutterBidmadCommon();
FlutterBaseInterstitial interstitial;
common.initInterstitialChannel().then((value) {
String _channelNm = value;
interstitial = FlutterBaseInterstitial(
channelName: _channelNm
);
interstitial.setAdInfo("Your Zone Id");
interstitial.setCallbackListener(
onLoadAd: (String zoneId){
print("interstitial onLoadAd");
},
onShowAd: (String zoneId){
print("interstitial onShowAd" );
interstitial.load(); //Ad Reload
},
onCloseAd: (String zoneId){
print("interstitial onCloseAd");
},
onFailAd: (String zoneId){
print("interstitial onFailAd");
}
);
});
....//Interstitial Load
interstitial.load();
....//Interstitial Show
interstitial.isLoaded().then((value){
if(value){
interstitial.show();
}
});
The following is an example of requesting a Reward ad.
....//Reward init
FlutterBidmadCommon common = FlutterBidmadCommon();
FlutterBaseReward reward;
common.initRewardChannel().then((value) {
String _channelNm = value;
reward = FlutterBaseReward(
channelName: _channelNm
);
reward.setAdInfo("Your Zone Id");
reward.setCallbackListener(
onLoadAd: (String zoneId){
print("reward onLoadAd");
},
onShowAd: (String zoneId){
print("reward onShowAd");
reward.load();
},
onCompleteAd: (String zoneId){
print("reward onCompleteAd");
},
onSkipAd: (String zoneId){
print("reward onSkippedAd");
},
onCloseAd: (String zoneId){
print("reward onCloseAd");
},
onClickAd: (String zoneId){
print("reward onClickAd");
},
onFailAd: (String zoneId){
print("reward onFailAd");
}
);
});
....//Reward Load
reward.load();
....//Reward Show
reward.isLoaded().then((value){
if(value){
reward.show();
}
});
reqAdTrackingAuthorization() displays a popup, requesting for App Tracking Consent from user. And the function will return set of number string values, showing the result.
FlutterBidmadCommon common = FlutterBidmadCommon();
common.reqAdTrackingAuthorization().then(
(value) {
switch (value) {
case "0":
print("App Tracking Not Determined");
break;
case "1":
print("App Tracking Restricted Authoriziation Status");
break;
case "2":
print("App Tracking Denied Authorization Status");
break;
case "3":
print("App Tracking Authorized Authorization Status");
break;
case "4":
print("user is on lower version than iOS 14");
break;
}
}
);
For App Tracking Not Determined, the function will return 0, For App Tracking Restricted Authoriziation Status, the function will return 1, For App Tracking Denied Authorization Status, the function will return 2, For App Tracking Authorized Authorization Status the function will return 3, and Lastly, if the user is on lower version than iOS 14 then it will return 4.
If you wish to obtain app tracking consent through a method other than what's provided by Plugin, If the user agrees, True, and if rejected, pass False to setAdvertiserTrackingEnabled.
common.setAdvertiserTrackingEnabled(false);
print(common.getAdvertiserTrackingEnabled());
*Banner ads are handled through FlutterBaseBanner and this is a list of functions for that.
Function | Description |
---|---|
FlutterBaseBanner(@required String channelName) | This is the FlutterBaseBanner constructor, Receives the Name for Channel creation as a Param. |
Future(void) load(int y) | Request a banner ad. When a banner ad is exposed, the banner is exposed at height y (center alignment). |
Future(void) loadWidget() | Request a banner ad. In order for the function to function properly, FlutterBaseBanner object must be obtained through the BidmadBannerWidget Class. |
Future(void) setInterval(int sec) | Set the banner refresh cycle.(60s~120s) |
Future(void) setAdInfo(String zoneId) | Set the issued ZoneId. |
Future(void) setCUID(String cuid) | Set the CUID property of each ad type. recommend encrypting text using sha256 or higher. |
Future(void) hideBanner() | Hide the banner View |
Future(void) showBanner() | Show the banner View. |
Future(void) removeBanner() | Remove the exposed banner. |
void Function(String zoneId) onLoadAd | If a listener is registered, the registered function is called when ad load. |
void Function(String zoneId) onFailAd | If a listener is registered, the registered function is called when ad load fail. |
*For banner ads in the form of a widget, it must be processed through BidmadBannerWidget, and this is a list of functions for that.
Function | Description |
---|---|
BidmadBannerWidget(BidmadBannerWidgetCreatedCallback onBidmadBannerWidgetCreated) | This is the BidmadBannerWidget constructor. After creating the widget, it receives a callback for processing. |
onBidmadBannerWidgetCreated(FlutterBaseBanner controller) | It is a callback that can receive a FlutterBaseBanner and handle banner related processing. |
*Interstitial ads are handled through FlutterBaseInterstitial and this is a list of functions for that.
Function | Description |
---|---|
FlutterBaseInterstitial(@required String channelName) | This is the FlutterBaseInterstitial constructor, Receives the Name for Channel creation as a Param. |
Future(void) load() | Request a interstitial ad |
Future(void) show() | Display the loaded interstitial ad |
Future(bool) isLoaded() | Check if the ad is loaded. |
Future(void) setAdInfo(String zoneId) | Set the issued ZoneId. |
Future(void) setCUID(String cuid) | Set the CUID property of each ad type. recommend encrypting text using sha256 or higher. |
void Function(String zoneId) onLoadAd | If a listener is registered, the registered function is called when ad load. |
void Function(String zoneId) onShowAd | If a listener is registered, the registered function is called when ad show. |
void Function(String zoneId) onFailAd | If a listener is registered, the registered function is called when ad load fail. |
void Function(String zoneId) onCloseAd | If a listener is registered, the registered function is called when ad close. |
*Reward ads are handled through FlutterBaseReward and this is a list of functions for that.
Function | Description |
---|---|
FlutterBaseReward(@required String channelName) | This is the FlutterBaseReward constructor, Receives the Name for Channel creation as a Param. |
Future(void) load() | Request a reward ad. |
Future(void) show() | Display the loaded reward ad. |
Future(bool) isLoaded() | Check if the ad is loaded. |
Future(void) setAdInfo(String zoneId) | Set the issued ZoneId. |
Future(void) setCUID(String cuid) | Set the CUID property of each ad type. recommend encrypting text using sha256 or higher. |
void Function(String zoneId) onLoadAd | If a listener is registered, the registered function is called when ad load. |
void Function(String zoneId) onShowAd | If a listener is registered, the registered function is called when ad show. |
void Function(String zoneId) onFailAd | If a listener is registered, the registered function is called when ad load fail. |
void Function(String zoneId) onCompleteAd | If a listener is registered, the registered function is called when ad complate. |
void Function(String zoneId) onCloseAd | If a listener is registered, the registered function is called when ad close. |
void Function(String zoneId) onClickAd | If a listener is registered, the registered function is called when ad click. |
void Function(String zoneId) onSkipAd | If a listener is registered, the registered function is called when ad skip. |
*This is a list of functions available through BidmadCommon.
Function | Description |
---|---|
FlutterBidmadCommon() | This is the FlutterBidmadCommon constructor |
Future(void) setDebugging(bool isDebug) | Debugging log output |
Future(void) initializeSdk() | Initialize BidmadSDK's supported ad networks |
Future(String) initBannerChannel() | Creating a channel for controlling banner ad |
Future(String) initInterstitialChannel() | Creating a channel for controlling interstitial ad |
Future(String) initRewardChannel() | Creating a channel for controlling reward ad |
Future(String) reqAdTrackingAuthorization() | Requesting for App Tracking Consent from user |
Future(void) setAdvertiserTrackingEnabled(bool enable) | Setting ATT Setting manually |
Future(bool) getAdvertiserTrackingEnabled() | Getting ATT Setting, true if consent and false if not consent |
Run this command:
With Flutter:
$ flutter pub add bidmad_plugin
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
bidmad_plugin: ^1.3.0
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:bidmad_plugin/BidmadBannerWidget.dart';
import 'package:bidmad_plugin/BidmadFlutterPlugin.dart';
import 'package:bidmad_plugin/FlutterBaseBanner.dart';
import 'package:bidmad_plugin/FlutterBaseInterstitial.dart';
import 'package:bidmad_plugin/FlutterBaseReward.dart';
import 'package:bidmad_plugin/FlutterBidmadCommon.dart';
import 'package:bidmad_plugin/FlutterBidmadGDPRforGoogle.dart';
Author:
Source code: https://pub.dev/packages/bidmad_plugin/install
License:
1656754874
在本文中,我们将学习如何在 Flutter 应用中为不同风格添加 Google 身份验证。
在本教程中,我们将了解不同生产阶段的定义及其在开发中的重要性。我们还将介绍如何在各种环境中使用不同的Firebase 配置。此外,我们将了解块小部件以及它们在 Flutter 应用程序中管理状态时的作用。
让我们创建一个 Flutter 项目来实现不同风格的 Google 身份验证,以便我们可以在我们的设备上拥有相同应用程序的不同版本进行测试。
在大型科技公司中,项目通常分三个阶段完成:开发、准备和生产(尽管这些阶段可能因公司而异)。
在这些不同的阶段,对产品进行彻底测试以处理错误,以便将高质量的软件产品交付给消费者。
在这一步中,UI的初始构建以及API和后端的集成都是在开发环境中完成的。您在此环境中使用的数据通常是测试 API 或测试数据库,并且没有任何数据是真实的。如果在发布后向应用程序添加新功能,它们将首先从开发环境中实现。
此阶段涉及大量代码测试,以确保代码功能齐全且应用程序高效运行。在此步骤中执行的测试类型称为unit testing
。
在测试环境中,可以引入选定的用户来测试应用程序。这可以让您很好地了解应用程序在启动时将如何工作,因为它可以与真实数据进行交互。测试环境试图模拟生产,因此即使出现重大故障并且系统出现故障,也不需要关闭生产。
在此阶段测试所有数据库迁移。添加新功能时,还会发送功能以检查最坏的情况。如果新功能在上传时出现问题,则会发现并修复错误。
如果您曾经使用过 WhatsApp Web,您可能会收到加入试用计划的请求,以便在新功能上线之前对其进行测试。这是所谓的 beta 测试的一个例子。
这是发布应用程序供用户试用的阶段。这是您的公司或客户最重要的阶段。在生产阶段,您不希望用户注意到任何重大错误,因为您最终可能会失去用户。理想情况下,到目前为止,软件中的大多数主要错误已经在早期阶段得到解决。
一般开发提示:您不必一次实现软件的所有功能。在发布新功能之前,优先考虑控制问题并确保当前功能稳定。
在 Flutter 应用程序中配置变体需要手动配置,这意味着我们将不得不处理不同目录中的许多文件。这可能会变得非常混乱,但是在very_good_cli的帮助下事情会容易得多。
要创建一个新的 Flutter 项目,我们将使用一个名为very_good_cli的 Dart 包。这个包将帮助我们创建一个标准框架并在我们的 iOS 和 Android 应用程序中配置我们需要的所有环境。
要安装该工具,请在终端中键入以下命令:dart pub global activate very_good_cli
安装并激活very_good_cli后,我们可以使用以下命令创建Flutter项目:very_good create my_app --desc "My new Flutter app" --org "com.custom.org"
将 YAML 文件的内容替换为以下内容:
name: googlesigninwithflavor
description: A Very Good Project created by Very Good CLI.
version: 1.0.0+1
publish_to: none
environment:
sdk: ">=2.16.0 <3.0.0"
dependencies:
bloc: ^8.0.3
flutter:
sdk: flutter
flutter_bloc: ^8.0.1
intl: ^0.17.0
google_sign_in: ^5.2.4
equatable: ^2.0.3
firebase_core: ^1.14.0
firebase_auth: ^3.3.13
dev_dependencies:
bloc_test: ^9.0.3
flutter_test:
sdk: flutter
mocktail: ^0.3.0
very_good_analysis: ^2.4.0
flutter:
uses-material-design: true
generate: true
assets:
- asset/
lib
├─ app
│ ├─ bloc
│ │ ├─ google_sign_in_bloc.dart
│ │ ├─ google_sign_in_event.dart
│ │ └─ google_sign_in_state.dart
│ ├─ view
│ │ ├─ app.dart
│ │ └─ google_sign_in_view.dart
│ └─ app.dart
├─ dashboard
│ └─ dashboard.dart
├─ repository
│ └─ authentication_repository.dart
├─ bootstrap.dart
├─ generated_plugin_registrant.dart
├─ main_development.dart
├─ main_production.dart
└─ main_staging.dart
当我们创建我们的项目时,我们会看到三个不同的核心文件,它们以生产的三个阶段命名。在生产的特定阶段,这些文件中的每一个都可以根据需要具有不同的设置。
main_development.dart
main_production.dart
main_staging.dart
我们可以通过将以下参数传递到我们的终端来运行任何风格:
# For Development
flutter run --flavor development --t lib/main_development.dart
# For Staging
flutter run --flavor development --t lib/main_staging.dart
# For Production
flutter run --flavor development --t lib/main_production.dart
对于Android,我们通常在配置不同风格时处理的build.gradle
文件是我们Android目录中的文件。
对于 iOS,我们将使用的文件是 Xcode 模式。但是,我们不需要这样做,因为very_good_cli 已经为我们生成了它们。
最近,Firebase推出了 Firebase CLI,它让 Firebase 项目的设置变得简单而无缝。但是,有些功能尚不受支持,例如分析和 Google 登录。由于我们将使用 Google 登录,因此我们需要手动配置 Firebase。因此,我们将手动配置我们的 Firebase 项目。
在我们的 Firebase 控制台中,我们将创建三个不同的项目,如下所示:
flavor dev
flavor stg
flavor prod
在 Firebase 上注册 Flutter 项目时,我们必须在Android 包的名称中添加.dev
、.stg
或。.prd
您可以在android/app/build.gradle
文件中找到包名称。显示为applicationId
,如下图。
defaultConfig {
applicationId "com.example.verygoodcore.googlesigninwithflavor"
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
flavorDimensions "default"
productFlavors {
production {
dimension "default"
applicationIdSuffix ""
manifestPlaceholders = [appName: "Googlesigninwithflavor"]
}
staging {
dimension "default"
applicationIdSuffix ".stg"
manifestPlaceholders = [appName: "[STG] Googlesigninwithflavor"]
}
development {
dimension "default"
applicationIdSuffix ".dev"
manifestPlaceholders = [appName: "[DEV] Googlesigninwithflavor"]
}
}
在注册 iOS 时,我们还需要输入正确的包 ID。但是,如果您以前没有使用 Xcode 的经验,则可能很难导航。我们可以通过以下步骤找到包 ID:
Abra 或 Xcode
单击Open a project or file
。
转到您的 Flutter 项目并打开 iOS 目录。选择Runner.xcworkspace
目录。
然后单击 Runner 下拉菜单。在 General View 选项卡中,选择Build Settings
,我们将在那里找到我们的应用程序包。
我们将对所有 Firebase 项目重复这些步骤。注册后,我们可以下载google-services.json
适用于Android和GoogleService-Info.plist
iOS的文件。
文件将google-services.json
移至android/app/src/{respective environment}
. 对于 iOS,我们将创建一个新的配置目录,其中包含我们环境的子目录并添加GoogleService-Info.plist
到各种环境中。Runner
让我们在 Xcode 中添加这个文件。阅读此Firebase 指南以了解更多信息。
要在我们的应用中使用 Google 身份验证,我们需要通过以下步骤启用 Google Provider。我们将在我们的开发环境中启用 Google Provider。
访问 Firebase。在本教程中,我们将从开发项目开始。
在主导航栏上,选择身份验证。您应该看到以下内容:
然后单击Set up sign-in method
。将显示提供者列表。选择谷歌登录,您将看到:
为项目激活Enable
并添加支持电子邮件,如下图所示。然后保存您的设置。
在导航栏上,单击设置图标并Project settings
从下拉列表中进行选择。然后滚动到页面底部。我们需要从我们的项目中添加一个SHA-1 key
和一个。SHA-256 key
要添加 SHA 密钥或指纹,我们将返回到我们的项目,右键单击 Android 文件夹,然后单击Open in an integrated terminal
。这应该会在我们的 VS Code 环境中为我们打开一个新终端。
在您的终端中使用命令./gradlew signingReport
获取密钥。运行此命令后,由于环境不同,我们应该会获得多个签名密钥。在终端中使用开发调试 SHA-1 密钥。
替代方案:在代码编辑器的终端中,您可以将目录更改为 Android 文件夹并运行命令。
单击保存按钮并下载google-services.json
更新的文件。替换google-services.json
开发环境中的文件。在我们的例子中,我们会将它添加到开发环境中。
注意: Firebase需要SHA-1 密钥才能使 Google 登录正常工作。
我们刚刚启用了 Google 身份验证!我们将在下一节中实现它。
我们将使用该块进行状态管理。Bloc 是添加的状态管理器very_good_cli
。
创建存储库
存储库就像一个服务,为我们的块提供我们需要发送到我们的 UI 层的数据。存储库负责根据块的请求进行直接 API 调用。我们将按如下方式实现我们的存储库:
import 'dart:developer';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthenticationRepository {
Future<bool> signInWithGoogle() async {
try {
final user = GoogleSignIn().currentUser ?? await GoogleSignIn().signIn();
if (user != null) {
await GoogleSignIn().signOut();
}
final googleAuth = await user?.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
await FirebaseAuth.instance.signInWithCredential(credential);
return true;
} catch (e) {
log('An Error Occurred $e');
return false;
}
}
Future<void> handleSignOut() => GoogleSignIn().disconnect();
// Future<void> signOut() async {
// final _googleSignIn = GoogleSignIn();
// _googleSignIn.disconnect();
// }
}
对于我们的项目,我们将需要两个事件,GoogleSignInRequested
并且GoogleSignOutRequested
. 我们可以通过以下方式实现:
part of 'google_sign_in_bloc.dart';
abstract class GoogleSignInEvent extends Equatable {
const GoogleSignInEvent();
@override
List<Object> get props => [];
}
class GoogleSignInRequested extends GoogleSignInEvent {}
class GoogleSignOutRequested extends GoogleSignInEvent {}
我们还需要两种状态——一种是当用户是Authenticated
时,一种是当用户是时UnAuthenticated
:
part of 'google_sign_in_bloc.dart';
abstract class GoogleSignInState extends Equatable {
@override
List<Object?> get props => [];
}
class UnAuthenticated extends GoogleSignInState {}
class Authenticated extends GoogleSignInState {}
我们的块将为我们的 UI 公开两种状态:Authenticated
用户登录时和UnAuthenticated
用户离开仪表板时。
让我们像这样实现它:
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:googlesigninwithflavor/repository/authentication_repository.dart';
part 'google_sign_in_event.dart';
part 'google_sign_in_state.dart';
class GoogleSignInBloc extends Bloc<GoogleSignInEvent, GoogleSignInState> {
GoogleSignInBloc({required this.authenticationRepository})
: super(UnAuthenticated()) {
on<GoogleSignInRequested>(_onGoogleSignInPressed);
on<GoogleSignOutRequested>(_onGoogleSignOutPressed);
}
final AuthenticationRepository authenticationRepository;
Future<void> _onGoogleSignInPressed(
GoogleSignInRequested event,
Emitter<GoogleSignInState> emit,
) async {
final response = await authenticationRepository.signInWithGoogle();
if (response) {
emit(Authenticated());
}
}
void _onGoogleSignOutPressed(
GoogleSignOutRequested event,
Emitter<GoogleSignInState> emit,
) {
authenticationRepository.handleSignOut();
emit(UnAuthenticated());
}
}
我们的app.dart
类将像这样渲染我们的启动屏幕:
import 'package:flutter/material.dart';
import 'package:googlesigninwithflavor/app/view/google_sign_in_view.dart';
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
appBarTheme: const AppBarTheme(color: Color(0xFF13B9FF)),
colorScheme: ColorScheme.fromSwatch(
accentColor: const Color(0xFF13B9FF),
),
),
home: const GoogleSignInView(),
);
}
}
google_sign_in_view.dart
将保留我们的启动画面和登录按钮的实现。
class GoogleSignInView extends StatelessWidget {
const GoogleSignInView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return RepositoryProvider(
create: (context) => AuthenticationRepository(),
child: BlocProvider(
create: (context) => GoogleSignInBloc(
authenticationRepository: RepositoryProvider.of(context),
),
child: Scaffold(
appBar: AppBar(
title: const Text('Sign In With Google'),
),
body: const ShowSignInButton(),
),
),
);
}
}
在上面的代码中,我们使用RepositoryProvider
小部件来创建我们的存储库的一个实例和一个孩子,它将使我们能够通过RepositoryProvider.of(context)
.
我们还使用BlocProvider
小部件来创建我们的实例,Bloc
以便子树或子小部件可以访问它。
然后我们将在我们的子小部件中使用该块,如下所示:
class ShowSignInButton extends StatelessWidget {
const ShowSignInButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocListener<GoogleSignInBloc, GoogleSignInState>(
listener: (context, state) {
if (state is Authenticated) {
Navigator.push<Type>(
context,
MaterialPageRoute(builder: (_) => const DashBoard()),
);
}
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Image.asset(
'asset/google2.png',
height: 60,
),
),
ElevatedButton(
onPressed: () {
context.read<GoogleSignInBloc>().add(GoogleSignInRequested());
},
child: const Text('Sign In With Google'),
),
],
),
);
}
}
在这里,我们使用BlocListner
来根据块发出的状态导航到不同的屏幕。
我们还将GoogleSignInRequested
事件传递给我们的ElevatedButton
,因此当用户单击按钮以使用 Google 登录时,该事件将传递给块并向GoogleSignIn
API 发出请求。
让我们也实现一个仪表板屏幕来显示经过身份验证的用户的详细信息。为了实现这一点,我们需要调用 Firebase Auth 实例来访问当前用户的详细信息。我们还将创建一个注销按钮,该按钮将使用BlocListner
小部件将用户带回登录屏幕:
class DashBoard extends StatelessWidget {
const DashBoard({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return RepositoryProvider(
create: (context) => AuthenticationRepository(),
child: BlocProvider(
create: (context) => GoogleSignInBloc(
authenticationRepository: RepositoryProvider.of(context),
),
child: DashBoardDetails(),
),
);
}
}
class DashBoardDetails extends StatelessWidget {
DashBoardDetails({
Key? key,
}) : super(key: key);
final user = FirebaseAuth.instance.currentUser!;
@override
Widget build(BuildContext context) {
return BlocListener<GoogleSignInBloc, GoogleSignInState>(
listener: (context, state) {
if (state is UnAuthenticated) {
Navigator.of(context).pushAndRemoveUntil<Type>(
MaterialPageRoute(builder: (context) => const GoogleSignInView()),
(route) => false,
);
}
},
child: Scaffold(
appBar: AppBar(
title: const Text('Very Good Codemagic'),
),
body: BlocBuilder<GoogleSignInBloc, GoogleSignInState>(
builder: (context, state) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Center(
child: Text('Welcome to your Dashboard'),
),
Text('${user.displayName}'),
if (user.photoURL != null)
Image.network('${user.photoURL}')
else
Container(),
ElevatedButton(
onPressed: () {
context
.read<GoogleSignInBloc>()
.add(GoogleSignOutRequested());
},
child: const Text('Sign Out'),
)
],
);
},
),
),
);
}
}
居住!🎉 我们刚刚为我们的开发、登台和生产环境成功创建了 Google 登录身份验证。
#flutter
Воробьёва Валерия Владимировна
1656754678
В этой статье мы узнаем, как добавить аутентификацию Google для разных вариантов вашего приложения Flutter.
В этом уроке мы узнаем определения различных этапов производства и их важность в разработке. Мы также расскажем, как использовать разные конфигурации Firebase в различных средах. Кроме того, мы узнаем о блочных виджетах и о том, что они делают при управлении нашим состоянием в нашем приложении Flutter.
Давайте создадим проект Flutter для реализации аутентификации Google для разных вариантов, чтобы у нас были разные версии одного и того же приложения на наших устройствах для тестирования.
В крупных технологических компаниях проекты обычно выполняются в три этапа: разработка, подготовка и производство (хотя эти этапы могут варьироваться от компании к компании).
На этих различных этапах продукты тщательно тестируются на наличие ошибок, чтобы высококачественные программные продукты могли быть отправлены потребителю.
На этом этапе начальное построение пользовательского интерфейса и интеграция API и серверной части выполняются в среде разработки. Данные, с которыми вы работаете в этой среде, обычно представляют собой тестовый API или тестовую базу данных, и никакие данные не являются реальными. Если новые функции будут добавлены в приложение после выпуска, они будут реализованы сначала из среды разработки.
Этот этап включает в себя много тестов кода, чтобы убедиться, что код полностью функционален, а приложение работает эффективно. Тип теста, выполняемого на этом этапе, называется unit testing
.
В тестовой среде для тестирования приложения можно привлечь выбранных пользователей. Это может дать вам хорошее представление о том, как приложение будет работать при запуске, поскольку оно может взаимодействовать с реальными данными. Среда тестирования пытается имитировать производственную среду, поэтому даже в случае серьезного сбоя и отказа системы производственную среду не нужно останавливать.
На этом этапе тестируются все миграции баз данных. Функции также отправляются для проверки наихудших сценариев при добавлении новых функций. Если новые функции ломаются при загрузке, ошибки будут найдены и исправлены.
Если вы когда-либо использовали WhatsApp Web, вы, вероятно, получали запрос на участие в пробной программе, чтобы протестировать новую функцию, прежде чем она будет запущена. Это пример так называемого бета-тестирования.
На этом этапе приложение выпускается для опробования пользователями. Это самый важный этап для вашей компании или клиента. На этапе производства вы не хотите, чтобы пользователи замечали какие-либо серьезные ошибки, так как вы можете потерять пользователей. В идеале, к этому моменту большинство основных ошибок в программном обеспечении уже были устранены на более ранних этапах.
Общий совет по разработке: вам не нужно реализовывать все функции программного обеспечения сразу. Расставьте приоритеты, контролируя проблемы и обеспечивая стабильность текущих функций, прежде чем выпускать новые.
Для настройки вариантов в нашем приложении Flutter требуется ручная настройка, а это значит, что нам придется работать со многими файлами в разных каталогах. Это может сильно запутать, но с помощью very_good_cli все может быть намного проще .
Чтобы создать новый проект Flutter, мы будем использовать пакет Dart с именем very_good_cli . Этот пакет поможет нам создать стандартную структуру и настроить все необходимые среды в нашем приложении для iOS и Android.
Чтобы установить инструмент, введите в терминале следующую команду:dart pub global activate very_good_cli
После установки и активации very_good_cli мы можем использовать следующую команду для создания проекта Flutter:very_good create my_app --desc "My new Flutter app" --org "com.custom.org"
Замените содержимое файла YAML следующим:
name: googlesigninwithflavor
description: A Very Good Project created by Very Good CLI.
version: 1.0.0+1
publish_to: none
environment:
sdk: ">=2.16.0 <3.0.0"
dependencies:
bloc: ^8.0.3
flutter:
sdk: flutter
flutter_bloc: ^8.0.1
intl: ^0.17.0
google_sign_in: ^5.2.4
equatable: ^2.0.3
firebase_core: ^1.14.0
firebase_auth: ^3.3.13
dev_dependencies:
bloc_test: ^9.0.3
flutter_test:
sdk: flutter
mocktail: ^0.3.0
very_good_analysis: ^2.4.0
flutter:
uses-material-design: true
generate: true
assets:
- asset/
lib
├─ app
│ ├─ bloc
│ │ ├─ google_sign_in_bloc.dart
│ │ ├─ google_sign_in_event.dart
│ │ └─ google_sign_in_state.dart
│ ├─ view
│ │ ├─ app.dart
│ │ └─ google_sign_in_view.dart
│ └─ app.dart
├─ dashboard
│ └─ dashboard.dart
├─ repository
│ └─ authentication_repository.dart
├─ bootstrap.dart
├─ generated_plugin_registrant.dart
├─ main_development.dart
├─ main_production.dart
└─ main_staging.dart
Когда мы создаем наш проект, мы видим три разных основных файла, названных в честь трех этапов производства. Каждый из этих файлов может иметь различные настройки, необходимые на данном этапе производства.
main_development.dart
main_production.dart
main_staging.dart
Мы можем запустить любой вариант, передав в наш терминал следующие аргументы:
# For Development
flutter run --flavor development --t lib/main_development.dart
# For Staging
flutter run --flavor development --t lib/main_staging.dart
# For Production
flutter run --flavor development --t lib/main_production.dart
Для Android файл, с которым мы обычно имеем дело при настройке различных вариантов, — это build.gradle
файл в нашем каталоге Android.
Для iOS файлы, с которыми мы будем работать, представляют собой схемы Xcode. Однако нам не нужно этого делать, так как они уже созданы для нас с помощью very_good_cli.
Недавно Firebase представила интерфейс командной строки Firebase, который упростил и упростил настройку проектов Firebase. Однако некоторые функции, такие как аналитика и вход через Google, пока не поддерживаются. Поскольку мы будем использовать Google Sign-in, нам нужно вручную настроить Firebase. Поэтому мы будем вручную настраивать наши проекты Firebase.
В нашей консоли Firebase мы создадим три разных проекта следующим образом:
flavor dev
flavor stg
flavor prod
При регистрации нашего проекта Flutter в Firebase мы должны добавить .dev
, .stg
или .prd
к имени нашего пакета Android.
Вы можете найти имя пакета в вашем android/app/build.gradle
файле. Он отображается как applicationId
, как показано ниже.
defaultConfig {
applicationId "com.example.verygoodcore.googlesigninwithflavor"
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
flavorDimensions "default"
productFlavors {
production {
dimension "default"
applicationIdSuffix ""
manifestPlaceholders = [appName: "Googlesigninwithflavor"]
}
staging {
dimension "default"
applicationIdSuffix ".stg"
manifestPlaceholders = [appName: "[STG] Googlesigninwithflavor"]
}
development {
dimension "default"
applicationIdSuffix ".dev"
manifestPlaceholders = [appName: "[DEV] Googlesigninwithflavor"]
}
}
При регистрации для iOS нам также необходимо ввести правильный идентификатор пакета. Однако в Xcode может быть сложно ориентироваться, если у вас нет предыдущего опыта работы с ним. Мы можем найти идентификатор пакета, выполнив следующие действия:
Абра или Xcode
Щелкните Open a project or file
.
Перейдите в свой проект Flutter и откройте каталог iOS. Выберите Runner.xcworkspace
каталог.
Затем щелкните раскрывающееся меню Runner. На вкладке «Общий вид» выберите Build Settings
, и мы сразу же найдем наш пакет приложений.
Мы повторим эти шаги для всех наших проектов Firebase. После регистрации мы можем скачать google-services.json
файл для Android и GoogleService-Info.plist
iOS.
Файлы google-services.json
будут перемещены в android/app/src/{respective environment}
. Для iOS мы создадим новый каталог конфигурации, в котором есть подкаталоги наших сред, и добавим GoogleService-Info.plist
их в различные среды. Давайте добавим этот файл Runner
в Xcode. Прочтите это руководство по Firebase для получения дополнительной информации.
Чтобы использовать аутентификацию Google в нашем приложении, нам нужно включить Google Provider, выполнив следующие действия. Мы включим Google Provider в нашей среде разработки.
Получите доступ к Firebase. В этом уроке мы начнем с проекта разработки.
На главной панели навигации выберите Аутентификация. Вы должны увидеть следующее:
Затем щелкните Set up sign-in method
. Отобразится список поставщиков. Выберите Google Login, и вы увидите это:
Активируйте Enable
и добавьте адрес электронной почты поддержки для проекта, как показано на изображении ниже. Затем сохраните настройки.
На панели навигации щелкните значок настроек и выберите Project settings
из раскрывающегося списка. Затем прокрутите страницу вниз. Нам нужно добавить a SHA-1 key
и a SHA-256 key
из нашего проекта.
Чтобы добавить ключи SHA или отпечатки пальцев, мы вернемся к нашему проекту, щелкнем правой кнопкой мыши папку Android и выберем Open in an integrated terminal
. Это должно открыть для нас новый терминал в нашей среде VS Code.
В вашем терминале используйте команду ./gradlew signingReport
для получения ключей. После запуска этой команды мы должны получить несколько ключей подписи из-за различных сред. Используйте отладочные ключи SHA-1 для разработки в своем терминале.
Альтернатива: в терминале вашего редактора кода вы можете изменить каталог на папку Android и запустить команду.
Нажмите кнопку «Сохранить» и загрузите google-services.json
обновленный файл. Замените google-services.json
файл в вашей среде разработки. В нашем случае мы добавим его в среду разработки.
Примечание. Ключ SHA-1 требуется Firebase для правильной работы входа через Google.
Мы только что включили аутентификацию Google! Мы реализуем это в следующем разделе.
Мы будем использовать блок для нашего управления состоянием. Bloc — менеджер состояний, добавленный very_good_cli
.
Создание репозитория
Репозиторий похож на службу, которая обслуживает наш блок данными, которые нам нужно отправить на наш уровень пользовательского интерфейса. Репозиторий отвечает за выполнение прямых вызовов API по запросу блока. Мы реализуем наш репозиторий следующим образом:
import 'dart:developer';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthenticationRepository {
Future<bool> signInWithGoogle() async {
try {
final user = GoogleSignIn().currentUser ?? await GoogleSignIn().signIn();
if (user != null) {
await GoogleSignIn().signOut();
}
final googleAuth = await user?.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
await FirebaseAuth.instance.signInWithCredential(credential);
return true;
} catch (e) {
log('An Error Occurred $e');
return false;
}
}
Future<void> handleSignOut() => GoogleSignIn().disconnect();
// Future<void> signOut() async {
// final _googleSignIn = GoogleSignIn();
// _googleSignIn.disconnect();
// }
}
Для нашего проекта нам понадобятся два события GoogleSignInRequested
и GoogleSignOutRequested
. Мы можем реализовать это следующим образом:
part of 'google_sign_in_bloc.dart';
abstract class GoogleSignInEvent extends Equatable {
const GoogleSignInEvent();
@override
List<Object> get props => [];
}
class GoogleSignInRequested extends GoogleSignInEvent {}
class GoogleSignOutRequested extends GoogleSignInEvent {}
Нам также понадобятся два состояния — одно, когда пользователь есть, Authenticated
и одно, когда пользователь UnAuthenticated
:
part of 'google_sign_in_bloc.dart';
abstract class GoogleSignInState extends Equatable {
@override
List<Object?> get props => [];
}
class UnAuthenticated extends GoogleSignInState {}
class Authenticated extends GoogleSignInState {}
Наш блок будет отображать два состояния нашего пользовательского интерфейса: Authenticated
когда пользователь вошел в систему и UnAuthenticated
когда пользователь покидает панель управления.
Давайте реализуем это так:
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:googlesigninwithflavor/repository/authentication_repository.dart';
part 'google_sign_in_event.dart';
part 'google_sign_in_state.dart';
class GoogleSignInBloc extends Bloc<GoogleSignInEvent, GoogleSignInState> {
GoogleSignInBloc({required this.authenticationRepository})
: super(UnAuthenticated()) {
on<GoogleSignInRequested>(_onGoogleSignInPressed);
on<GoogleSignOutRequested>(_onGoogleSignOutPressed);
}
final AuthenticationRepository authenticationRepository;
Future<void> _onGoogleSignInPressed(
GoogleSignInRequested event,
Emitter<GoogleSignInState> emit,
) async {
final response = await authenticationRepository.signInWithGoogle();
if (response) {
emit(Authenticated());
}
}
void _onGoogleSignOutPressed(
GoogleSignOutRequested event,
Emitter<GoogleSignInState> emit,
) {
authenticationRepository.handleSignOut();
emit(UnAuthenticated());
}
}
Наш app.dart
класс будет отображать наш экран-заставку следующим образом:
import 'package:flutter/material.dart';
import 'package:googlesigninwithflavor/app/view/google_sign_in_view.dart';
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
appBarTheme: const AppBarTheme(color: Color(0xFF13B9FF)),
colorScheme: ColorScheme.fromSwatch(
accentColor: const Color(0xFF13B9FF),
),
),
home: const GoogleSignInView(),
);
}
}
google_sign_in_view.dart
сохранит реализацию нашего экрана-заставки и кнопку входа в систему.
class GoogleSignInView extends StatelessWidget {
const GoogleSignInView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return RepositoryProvider(
create: (context) => AuthenticationRepository(),
child: BlocProvider(
create: (context) => GoogleSignInBloc(
authenticationRepository: RepositoryProvider.of(context),
),
child: Scaffold(
appBar: AppBar(
title: const Text('Sign In With Google'),
),
body: const ShowSignInButton(),
),
),
);
}
}
В приведенном выше коде мы используем RepositoryProvider
виджет для создания экземпляра нашего репозитория и дочернего элемента, который даст нам доступ к репозиторию через файлы RepositoryProvider.of(context)
.
Мы также используем BlocProvider
виджет для создания своего экземпляра, Bloc
чтобы к нему можно было получить доступ из поддерева или дочерних виджетов.
Затем мы будем использовать блок в наших дочерних виджетах следующим образом:
class ShowSignInButton extends StatelessWidget {
const ShowSignInButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocListener<GoogleSignInBloc, GoogleSignInState>(
listener: (context, state) {
if (state is Authenticated) {
Navigator.push<Type>(
context,
MaterialPageRoute(builder: (_) => const DashBoard()),
);
}
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Image.asset(
'asset/google2.png',
height: 60,
),
),
ElevatedButton(
onPressed: () {
context.read<GoogleSignInBloc>().add(GoogleSignInRequested());
},
child: const Text('Sign In With Google'),
),
],
),
);
}
}
Здесь мы используем BlocListner
для перехода к другому экрану в зависимости от состояния, испускаемого блоком.
Мы также передаем GoogleSignInRequested
событие в наш ElevatedButton
, поэтому, когда пользователь нажимает кнопку для входа в Google, событие передается в блок и делается запрос к GoogleSignIn
API.
Давайте также реализуем экран панели инструментов для отображения сведений о аутентифицированном пользователе. Чтобы реализовать это, нам нужно вызвать экземпляр Firebase Auth, чтобы получить доступ к данным текущего пользователя. Мы также создадим кнопку выхода, которая вернет пользователя на экран входа с помощью BlocListner
виджета:
class DashBoard extends StatelessWidget {
const DashBoard({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return RepositoryProvider(
create: (context) => AuthenticationRepository(),
child: BlocProvider(
create: (context) => GoogleSignInBloc(
authenticationRepository: RepositoryProvider.of(context),
),
child: DashBoardDetails(),
),
);
}
}
class DashBoardDetails extends StatelessWidget {
DashBoardDetails({
Key? key,
}) : super(key: key);
final user = FirebaseAuth.instance.currentUser!;
@override
Widget build(BuildContext context) {
return BlocListener<GoogleSignInBloc, GoogleSignInState>(
listener: (context, state) {
if (state is UnAuthenticated) {
Navigator.of(context).pushAndRemoveUntil<Type>(
MaterialPageRoute(builder: (context) => const GoogleSignInView()),
(route) => false,
);
}
},
child: Scaffold(
appBar: AppBar(
title: const Text('Very Good Codemagic'),
),
body: BlocBuilder<GoogleSignInBloc, GoogleSignInState>(
builder: (context, state) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Center(
child: Text('Welcome to your Dashboard'),
),
Text('${user.displayName}'),
if (user.photoURL != null)
Image.network('${user.photoURL}')
else
Container(),
ElevatedButton(
onPressed: () {
context
.read<GoogleSignInBloc>()
.add(GoogleSignOutRequested());
},
child: const Text('Sign Out'),
)
],
);
},
),
),
);
}
}
Жить! 🎉 Мы только что успешно создали аутентификацию входа через Google для наших сред разработки, промежуточной и производственной среды.
источник: https://blog.codemagic.io
#flutter
1656750905
This library allows you to play a wizard game.
Run this command:
With Dart:
$ dart pub add question_wizard
With Flutter:
$ flutter pub add question_wizard
This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get
):
dependencies:
question_wizard: ^0.0.1
Alternatively, your editor might support dart pub get
or flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:question_wizard/question_wizard.dart';
example/main.dart
import 'package:question_wizard/question_wizard.dart';
void main() {
final List<Option> options = [
new Option(label: 'choose a blue color', value: '#0000FF'),
new Option(label: 'choose a green color', value: '#00FF00'),
];
Prompter prompter = Prompter();
String? colorCode = prompter.askMultiple('select a color:', options);
bool answer = prompter.askBinary('do you like this package 🥰');
if (answer) {
print("thank's a lot buddy 😊");
} else {
print("I know that's not a great package. 😔");
}
}
Original article source at: https://pub.dev/packages/question_wizard
1656746848
TODO: Put a short description of the package here that helps potential users know whether this package might be useful for them.
TODO: List what your package can do. Maybe include images, gifs, or videos.
TODO: List prerequisites and provide or point to information on how to start using the package.
TODO: Include short and useful examples for package users. Add longer examples to /example
folder.
const like = 'sample';
TODO: Tell users more about the package: where to find more information, how to contribute to the package, how to file issues, what response they can expect from the package authors, and more.
Run this command:
With Flutter:
$ flutter pub add smart_dropdown_field
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
smart_dropdown_field: ^0.0.1
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:smart_dropdown_field/smart_dropdown_field.dart';
Download Details:
Author: PhilipPurwoko
Source Code: https://github.com/PhilipPurwoko/smart_dropdown_field
1656746603
Plugin providing shared preferences inspector capabilities for local storage inspector.
See https://pub.dev/packages/storage_inspector
Run this command:
With Flutter:
$ flutter pub add preferences_local_storage_inspector
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
preferences_local_storage_inspector: ^0.2.3
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:preferences_local_storage_inspector/preferences_local_storage_inspector.dart';
import 'package:flutter/material.dart';
import 'package:preferences_local_storage_inspector/preferences_local_storage_inspector.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:storage_inspector/storage_inspector.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// ignore: avoid_print
storageInspectorLogger = (e) => print(e);
final preferences = await SharedPreferences.getInstance();
final driver = StorageServerDriver(
bundleId: 'com.example.test',
icon: '<some icon>',
);
final keyValueServer =
PreferencesKeyValueServer(preferences, 'Preferences', keySuggestions: {
const ValueWithType(StorageType.string, 'testBool'),
const ValueWithType(StorageType.string, 'testInt'),
const ValueWithType(StorageType.string, 'testFloat'),
});
driver.addKeyValueServer(keyValueServer);
// Don't wait for a connection from the instrumentation driver
await driver.start(paused: false);
// run app
await Future<void>.delayed(const Duration(minutes: 15));
await driver.stop(); //Optional when main ends
}
Download Details:
Author: NicolaVerbeeck
Source Code: https://github.com/NicolaVerbeeck/flutter_local_storage_inspector
1656746160
This project implements Dart definitions and API helpers for the Bungie.net API. It's based on bungie-api-ts that is meant for use in Destiny Item Manager, but should be general enough to use in any project. The code is completely generated from Bungie's documentation - I considered using something like Swagger Codegen, but instead opted for a custom generator so we could make the result as nice as possible.
Install
add this to your dependencies block in pubspec.yaml
dependencies:
bungie_api: ^12.2.4
Interfaces and Enums
There are definitions for every type defined in the Bungie.net services. See their documentation for a list - the interface names are the last part of the full name (for example, Destiny.Definitions.DestinyVendorActionDefinition
becomes DestinyVendorActionDefinition
). There are a few exceptions, like SingleComponentResponseOfDestinyInventoryComponent
, which have been mapped into nicer forms like SingleComponentResponse<DestinyInventoryComponent>
, and the server responses, which are now ServerResponse<T>
instead of something like DestinyCharacterResponse
.
API Helpers
In addition to the types, there are also simple helper functions for each API endpoint. They define the inputs and outputs to that endpoint, and will call a user-provided function with HTTP request info that you can then use to make an HTTP request. This pattern was used so the API helpers could provide full type information. These helpers are not a full API client - they assist in building one. An example:
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:bungie_api_dart/destiny2.dart';
class BungieApiService{
Future<ServerResponse<DestinyManifest>> getManifest(){
return getDestinyManifest(new Client());
}
}
class Client implements HttpClient{
static const API_KEY = "your_key";
@override
Future<Object> request(HttpClientConfig config) {
if(config.method == 'GET'){
return http.get(config.url, headers: {'X-API-Key': API_KEY});
}
return http.post(config.url, headers: {'X-API-Key': API_KEY});
}
}
Build
./install.sh && ./build.sh
Installing
Run this command:
With Dart:
$ dart pub add bungie_api
With Flutter:
$ flutter pub add bungie_api
This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get
):
dependencies:
bungie_api: ^13.14.0
Alternatively, your editor might support dart pub get
or flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:bungie_api/api/app.dart';
import 'package:bungie_api/api/community_content.dart';
import 'package:bungie_api/api/content.dart';
import 'package:bungie_api/api/destiny2.dart';
import 'package:bungie_api/api/fireteam.dart';
import 'package:bungie_api/api/forum.dart';
import 'package:bungie_api/api/get_available_locales.dart';
import 'package:bungie_api/api/global_alerts.dart';
import 'package:bungie_api/api/group_v2.dart';
import 'package:bungie_api/api/settings.dart';
import 'package:bungie_api/api/social.dart';
import 'package:bungie_api/api/tokens.dart';
import 'package:bungie_api/api/trending.dart';
import 'package:bungie_api/api/user.dart';
import 'package:bungie_api/api/user_system_overrides.dart';
import 'package:bungie_api/app.dart';
import 'package:bungie_api/applications.dart';
import 'package:bungie_api/common.dart';
import 'package:bungie_api/communitycontent.dart';
import 'package:bungie_api/components.dart';
import 'package:bungie_api/config.dart';
import 'package:bungie_api/content.dart';
import 'package:bungie_api/core.dart';
import 'package:bungie_api/dates.dart';
import 'package:bungie_api/destiny2.dart';
import 'package:bungie_api/entities.dart';
import 'package:bungie_api/enums/activity_graph_node_highlight_type.dart';
import 'package:bungie_api/enums/application_scopes.dart';
import 'package:bungie_api/enums/application_status.dart';
import 'package:bungie_api/enums/awa_response_reason.dart';
import 'package:bungie_api/enums/awa_type.dart';
import 'package:bungie_api/enums/awa_user_selection.dart';
import 'package:bungie_api/enums/bucket_category.dart';
import 'package:bungie_api/enums/bucket_scope.dart';
import 'package:bungie_api/enums/bungie_credential_type.dart';
import 'package:bungie_api/enums/bungie_membership_type.dart';
import 'package:bungie_api/enums/capabilities.dart';
import 'package:bungie_api/enums/chat_security_setting.dart';
import 'package:bungie_api/enums/community_content_sort_mode.dart';
import 'package:bungie_api/enums/component_privacy_setting.dart';
import 'package:bungie_api/enums/content_property_data_type_enum.dart';
import 'package:bungie_api/enums/damage_type.dart';
import 'package:bungie_api/enums/destiny_activity_difficulty_tier.dart';
import 'package:bungie_api/enums/destiny_activity_mode_category.dart';
import 'package:bungie_api/enums/destiny_activity_mode_type.dart';
import 'package:bungie_api/enums/destiny_activity_nav_point_type.dart';
import 'package:bungie_api/enums/destiny_ammunition_type.dart';
import 'package:bungie_api/enums/destiny_breaker_type.dart';
import 'package:bungie_api/enums/destiny_class.dart';
import 'package:bungie_api/enums/destiny_collectible_state.dart';
import 'package:bungie_api/enums/destiny_component_type.dart';
import 'package:bungie_api/enums/destiny_energy_type.dart';
import 'package:bungie_api/enums/destiny_game_privacy_setting.dart';
import 'package:bungie_api/enums/destiny_game_versions.dart';
import 'package:bungie_api/enums/destiny_gating_scope.dart';
import 'package:bungie_api/enums/destiny_gender.dart';
import 'package:bungie_api/enums/destiny_graph_node_state.dart';
import 'package:bungie_api/enums/destiny_item_sort_type.dart';
import 'package:bungie_api/enums/destiny_item_sub_type.dart';
import 'package:bungie_api/enums/destiny_item_type.dart';
import 'package:bungie_api/enums/destiny_join_closed_reasons.dart';
import 'package:bungie_api/enums/destiny_milestone_display_preference.dart';
import 'package:bungie_api/enums/destiny_milestone_type.dart';
import 'package:bungie_api/enums/destiny_objective_grant_style.dart';
import 'package:bungie_api/enums/destiny_objective_ui_style.dart';
import 'package:bungie_api/enums/destiny_party_member_states.dart';
import 'package:bungie_api/enums/destiny_presentation_display_style.dart';
import 'package:bungie_api/enums/destiny_presentation_node_state.dart';
import 'package:bungie_api/enums/destiny_presentation_node_type.dart';
import 'package:bungie_api/enums/destiny_presentation_screen_style.dart';
import 'package:bungie_api/enums/destiny_progression_reward_item_acquisition_behavior.dart';
import 'package:bungie_api/enums/destiny_progression_reward_item_state.dart';
import 'package:bungie_api/enums/destiny_progression_scope.dart';
import 'package:bungie_api/enums/destiny_progression_step_display_effect.dart';
import 'package:bungie_api/enums/destiny_race.dart';
import 'package:bungie_api/enums/destiny_record_state.dart';
import 'package:bungie_api/enums/destiny_record_toast_style.dart';
import 'package:bungie_api/enums/destiny_record_value_style.dart';
import 'package:bungie_api/enums/destiny_reward_source_category.dart';
import 'package:bungie_api/enums/destiny_scope.dart';
import 'package:bungie_api/enums/destiny_socket_array_type.dart';
import 'package:bungie_api/enums/destiny_socket_category_style.dart';
import 'package:bungie_api/enums/destiny_socket_visibility.dart';
import 'package:bungie_api/enums/destiny_stat_aggregation_type.dart';
import 'package:bungie_api/enums/destiny_stat_category.dart';
import 'package:bungie_api/enums/destiny_stats_category_type.dart';
import 'package:bungie_api/enums/destiny_stats_group_type.dart';
import 'package:bungie_api/enums/destiny_stats_merge_method.dart';
import 'package:bungie_api/enums/destiny_talent_node_state.dart';
import 'package:bungie_api/enums/destiny_talent_node_step_damage_types.dart';
import 'package:bungie_api/enums/destiny_talent_node_step_guardian_attributes.dart';
import 'package:bungie_api/enums/destiny_talent_node_step_impact_effects.dart';
import 'package:bungie_api/enums/destiny_talent_node_step_light_abilities.dart';
import 'package:bungie_api/enums/destiny_talent_node_step_weapon_performances.dart';
import 'package:bungie_api/enums/destiny_unlock_value_uistyle.dart';
import 'package:bungie_api/enums/destiny_vendor_filter.dart';
import 'package:bungie_api/enums/destiny_vendor_interaction_reward_selection.dart';
import 'package:bungie_api/enums/destiny_vendor_item_refund_policy.dart';
import 'package:bungie_api/enums/destiny_vendor_item_state.dart';
import 'package:bungie_api/enums/destiny_vendor_progression_type.dart';
import 'package:bungie_api/enums/destiny_vendor_reply_type.dart';
import 'package:bungie_api/enums/developer_role.dart';
import 'package:bungie_api/enums/equip_failure_reason.dart';
import 'package:bungie_api/enums/equipping_item_block_attributes.dart';
import 'package:bungie_api/enums/fireteam_date_range.dart';
import 'package:bungie_api/enums/fireteam_platform.dart';
import 'package:bungie_api/enums/fireteam_platform_invite_result.dart';
import 'package:bungie_api/enums/fireteam_public_search_option.dart';
import 'package:bungie_api/enums/fireteam_slot_search.dart';
import 'package:bungie_api/enums/forum_flags_enum.dart';
import 'package:bungie_api/enums/forum_media_type.dart';
import 'package:bungie_api/enums/forum_post_category_enums.dart';
import 'package:bungie_api/enums/forum_post_popularity.dart';
import 'package:bungie_api/enums/forum_post_sort_enum.dart';
import 'package:bungie_api/enums/forum_recruitment_intensity_label.dart';
import 'package:bungie_api/enums/forum_recruitment_tone_label.dart';
import 'package:bungie_api/enums/forum_topics_category_filters_enum.dart';
import 'package:bungie_api/enums/forum_topics_quick_date_enum.dart';
import 'package:bungie_api/enums/forum_topics_sort_enum.dart';
import 'package:bungie_api/enums/friend_relationship_state.dart';
import 'package:bungie_api/enums/global_alert_level.dart';
import 'package:bungie_api/enums/global_alert_type.dart';
import 'package:bungie_api/enums/group_alliance_status.dart';
import 'package:bungie_api/enums/group_application_resolve_state.dart';
import 'package:bungie_api/enums/group_date_range.dart';
import 'package:bungie_api/enums/group_homepage.dart';
import 'package:bungie_api/enums/group_member_count_filter.dart';
import 'package:bungie_api/enums/group_post_publicity.dart';
import 'package:bungie_api/enums/group_potential_member_status.dart';
import 'package:bungie_api/enums/group_sort_by.dart';
import 'package:bungie_api/enums/group_type.dart';
import 'package:bungie_api/enums/groups_for_member_filter.dart';
import 'package:bungie_api/enums/host_guided_games_permission_level.dart';
import 'package:bungie_api/enums/ignore_length.dart';
import 'package:bungie_api/enums/ignore_status.dart';
import 'package:bungie_api/enums/item_bind_status.dart';
import 'package:bungie_api/enums/item_location.dart';
import 'package:bungie_api/enums/item_perk_visibility.dart';
import 'package:bungie_api/enums/item_state.dart';
import 'package:bungie_api/enums/membership_option.dart';
import 'package:bungie_api/enums/opt_in_flags.dart';
import 'package:bungie_api/enums/period_type.dart';
import 'package:bungie_api/enums/platform_error_codes.dart';
import 'package:bungie_api/enums/platform_friend_type.dart';
import 'package:bungie_api/enums/plug_availability_mode.dart';
import 'package:bungie_api/enums/plug_ui_styles.dart';
import 'package:bungie_api/enums/presence_online_state_flags.dart';
import 'package:bungie_api/enums/presence_status.dart';
import 'package:bungie_api/enums/runtime_group_member_type.dart';
import 'package:bungie_api/enums/socket_plug_sources.dart';
import 'package:bungie_api/enums/socket_type_action_type.dart';
import 'package:bungie_api/enums/special_item_type.dart';
import 'package:bungie_api/enums/tier_type.dart';
import 'package:bungie_api/enums/transfer_statuses.dart';
import 'package:bungie_api/enums/trending_entry_type.dart';
import 'package:bungie_api/enums/unit_type.dart';
import 'package:bungie_api/enums/vendor_display_category_sort_order.dart';
import 'package:bungie_api/enums/vendor_interaction_type.dart';
import 'package:bungie_api/enums/vendor_item_status.dart';
import 'package:bungie_api/exceptions.dart';
import 'package:bungie_api/fireteam.dart';
import 'package:bungie_api/forum.dart';
import 'package:bungie_api/forums.dart';
import 'package:bungie_api/getavailablelocales.dart';
import 'package:bungie_api/globalalerts.dart';
import 'package:bungie_api/groupsv2.dart';
import 'package:bungie_api/groupv2.dart';
import 'package:bungie_api/helpers/base_bungie_net_response.dart';
import 'package:bungie_api/helpers/bungie_net_token.dart';
import 'package:bungie_api/helpers/http.dart';
import 'package:bungie_api/helpers/oauth.dart';
import 'package:bungie_api/ignores.dart';
import 'package:bungie_api/interpolation.dart';
import 'package:bungie_api/links.dart';
import 'package:bungie_api/models/api_usage.dart';
import 'package:bungie_api/models/application.dart';
import 'package:bungie_api/models/application_developer.dart';
import 'package:bungie_api/models/awa_authorization_result.dart';
import 'package:bungie_api/models/awa_initialize_response.dart';
import 'package:bungie_api/models/awa_permission_requested.dart';
import 'package:bungie_api/models/awa_user_response.dart';
import 'package:bungie_api/models/bungie_friend.dart';
import 'package:bungie_api/models/bungie_friend_list_response.dart';
import 'package:bungie_api/models/bungie_friend_request_list_response.dart';
import 'package:bungie_api/models/clan_banner.dart';
import 'package:bungie_api/models/clan_banner_decal.dart';
import 'package:bungie_api/models/clan_banner_source.dart';
import 'package:bungie_api/models/comment_summary.dart';
import 'package:bungie_api/models/component_response.dart';
import 'package:bungie_api/models/content_item_public_contract.dart';
import 'package:bungie_api/models/content_preview.dart';
import 'package:bungie_api/models/content_representation.dart';
import 'package:bungie_api/models/content_type_default_value.dart';
import 'package:bungie_api/models/content_type_description.dart';
import 'package:bungie_api/models/content_type_property.dart';
import 'package:bungie_api/models/content_type_property_section.dart';
import 'package:bungie_api/models/core_setting.dart';
import 'package:bungie_api/models/core_settings_configuration.dart';
import 'package:bungie_api/models/core_system.dart';
import 'package:bungie_api/models/cross_save_user_membership.dart';
import 'package:bungie_api/models/datapoint.dart';
import 'package:bungie_api/models/date_range.dart';
import 'package:bungie_api/models/destiny2_core_settings.dart';
import 'package:bungie_api/models/destiny_action_request.dart';
import 'package:bungie_api/models/destiny_activity.dart';
import 'package:bungie_api/models/destiny_activity_challenge_definition.dart';
import 'package:bungie_api/models/destiny_activity_definition.dart';
import 'package:bungie_api/models/destiny_activity_graph_art_element_definition.dart';
import 'package:bungie_api/models/destiny_activity_graph_connection_definition.dart';
import 'package:bungie_api/models/destiny_activity_graph_definition.dart';
import 'package:bungie_api/models/destiny_activity_graph_display_objective_definition.dart';
import 'package:bungie_api/models/destiny_activity_graph_display_progression_definition.dart';
import 'package:bungie_api/models/destiny_activity_graph_list_entry_definition.dart';
import 'package:bungie_api/models/destiny_activity_graph_node_activity_definition.dart';
import 'package:bungie_api/models/destiny_activity_graph_node_definition.dart';
import 'package:bungie_api/models/destiny_activity_graph_node_featuring_state_definition.dart';
import 'package:bungie_api/models/destiny_activity_graph_node_state_entry.dart';
import 'package:bungie_api/models/destiny_activity_guided_block_definition.dart';
import 'package:bungie_api/models/destiny_activity_history_results.dart';
import 'package:bungie_api/models/destiny_activity_insertion_point_definition.dart';
import 'package:bungie_api/models/destiny_activity_loadout_requirement.dart';
import 'package:bungie_api/models/destiny_activity_loadout_requirement_set.dart';
import 'package:bungie_api/models/destiny_activity_matchmaking_block_definition.dart';
import 'package:bungie_api/models/destiny_activity_mode_definition.dart';
import 'package:bungie_api/models/destiny_activity_modifier_definition.dart';
import 'package:bungie_api/models/destiny_activity_modifier_reference_definition.dart';
import 'package:bungie_api/models/destiny_activity_playlist_item_definition.dart';
import 'package:bungie_api/models/destiny_activity_reward_definition.dart';
import 'package:bungie_api/models/destiny_activity_type_definition.dart';
import 'package:bungie_api/models/destiny_activity_unlock_string_definition.dart';
import 'package:bungie_api/models/destiny_aggregate_activity_results.dart';
import 'package:bungie_api/models/destiny_aggregate_activity_stats.dart';
import 'package:bungie_api/models/destiny_animation_reference.dart';
import 'package:bungie_api/models/destiny_art_dye_reference.dart';
import 'package:bungie_api/models/destiny_artifact_character_scoped.dart';
import 'package:bungie_api/models/destiny_artifact_definition.dart';
import 'package:bungie_api/models/destiny_artifact_profile_scoped.dart';
import 'package:bungie_api/models/destiny_artifact_tier.dart';
import 'package:bungie_api/models/destiny_artifact_tier_definition.dart';
import 'package:bungie_api/models/destiny_artifact_tier_item.dart';
import 'package:bungie_api/models/destiny_artifact_tier_item_definition.dart';
import 'package:bungie_api/models/destiny_base_item_component_set_ofint32.dart';
import 'package:bungie_api/models/destiny_base_item_component_set_ofint64.dart';
import 'package:bungie_api/models/destiny_base_item_component_set_ofuint32.dart';
import 'package:bungie_api/models/destiny_breaker_type_definition.dart';
import 'package:bungie_api/models/destiny_bubble_definition.dart';
import 'package:bungie_api/models/destiny_challenge_status.dart';
import 'package:bungie_api/models/destiny_character_action_request.dart';
import 'package:bungie_api/models/destiny_character_activities_component.dart';
import 'package:bungie_api/models/destiny_character_component.dart';
import 'package:bungie_api/models/destiny_character_customization.dart';
import 'package:bungie_api/models/destiny_character_peer_view.dart';
import 'package:bungie_api/models/destiny_character_progression_component.dart';
import 'package:bungie_api/models/destiny_character_records_component.dart';
import 'package:bungie_api/models/destiny_character_render_component.dart';
import 'package:bungie_api/models/destiny_character_response.dart';
import 'package:bungie_api/models/destiny_checklist_definition.dart';
import 'package:bungie_api/models/destiny_checklist_entry_definition.dart';
import 'package:bungie_api/models/destiny_clan_aggregate_stat.dart';
import 'package:bungie_api/models/destiny_class_definition.dart';
import 'package:bungie_api/models/destiny_collectible_acquisition_block.dart';
import 'package:bungie_api/models/destiny_collectible_component.dart';
import 'package:bungie_api/models/destiny_collectible_definition.dart';
import 'package:bungie_api/models/destiny_collectible_node_detail_response.dart';
import 'package:bungie_api/models/destiny_collectible_state_block.dart';
import 'package:bungie_api/models/destiny_collectibles_component.dart';
import 'package:bungie_api/models/destiny_color.dart';
import 'package:bungie_api/models/destiny_craftable_component.dart';
import 'package:bungie_api/models/destiny_craftable_socket_component.dart';
import 'package:bungie_api/models/destiny_craftable_socket_plug_component.dart';
import 'package:bungie_api/models/destiny_craftables_component.dart';
import 'package:bungie_api/models/destiny_currencies_component.dart';
import 'package:bungie_api/models/destiny_damage_type_definition.dart';
import 'package:bungie_api/models/destiny_definition.dart';
import 'package:bungie_api/models/destiny_derived_item_category_definition.dart';
import 'package:bungie_api/models/destiny_derived_item_definition.dart';
import 'package:bungie_api/models/destiny_destination_bubble_setting_definition.dart';
import 'package:bungie_api/models/destiny_destination_definition.dart';
import 'package:bungie_api/models/destiny_display_category_definition.dart';
import 'package:bungie_api/models/destiny_display_properties_definition.dart';
import 'package:bungie_api/models/destiny_energy_capacity_entry.dart';
import 'package:bungie_api/models/destiny_energy_cost_entry.dart';
import 'package:bungie_api/models/destiny_energy_type_definition.dart';
import 'package:bungie_api/models/destiny_entity_search_result.dart';
import 'package:bungie_api/models/destiny_entity_search_result_item.dart';
import 'package:bungie_api/models/destiny_environment_location_mapping.dart';
import 'package:bungie_api/models/destiny_equip_item_result.dart';
import 'package:bungie_api/models/destiny_equip_item_results.dart';
import 'package:bungie_api/models/destiny_equipment_slot_definition.dart';
import 'package:bungie_api/models/destiny_equipping_block_definition.dart';
import 'package:bungie_api/models/destiny_error_profile.dart';
import 'package:bungie_api/models/destiny_faction_definition.dart';
import 'package:bungie_api/models/destiny_faction_progression.dart';
import 'package:bungie_api/models/destiny_faction_vendor_definition.dart';
import 'package:bungie_api/models/destiny_gear_art_arrangement_reference.dart';
import 'package:bungie_api/models/destiny_gender_definition.dart';
import 'package:bungie_api/models/destiny_historical_stats_account_result.dart';
import 'package:bungie_api/models/destiny_historical_stats_activity.dart';
import 'package:bungie_api/models/destiny_historical_stats_by_period.dart';
import 'package:bungie_api/models/destiny_historical_stats_definition.dart';
import 'package:bungie_api/models/destiny_historical_stats_per_character.dart';
import 'package:bungie_api/models/destiny_historical_stats_period_group.dart';
import 'package:bungie_api/models/destiny_historical_stats_results.dart';
import 'package:bungie_api/models/destiny_historical_stats_value.dart';
import 'package:bungie_api/models/destiny_historical_stats_value_pair.dart';
import 'package:bungie_api/models/destiny_historical_stats_with_merged.dart';
import 'package:bungie_api/models/destiny_historical_weapon_stats.dart';
import 'package:bungie_api/models/destiny_historical_weapon_stats_data.dart';
import 'package:bungie_api/models/destiny_icon_sequence_definition.dart';
import 'package:bungie_api/models/destiny_insert_plug_action_definition.dart';
import 'package:bungie_api/models/destiny_insert_plugs_action_request.dart';
import 'package:bungie_api/models/destiny_insert_plugs_free_action_request.dart';
import 'package:bungie_api/models/destiny_insert_plugs_request_entry.dart';
import 'package:bungie_api/models/destiny_inventory_bucket_definition.dart';
import 'package:bungie_api/models/destiny_inventory_component.dart';
import 'package:bungie_api/models/destiny_inventory_item_definition.dart';
import 'package:bungie_api/models/destiny_inventory_item_stat_definition.dart';
import 'package:bungie_api/models/destiny_item_action_block_definition.dart';
import 'package:bungie_api/models/destiny_item_action_request.dart';
import 'package:bungie_api/models/destiny_item_action_required_item_definition.dart';
import 'package:bungie_api/models/destiny_item_category_definition.dart';
import 'package:bungie_api/models/destiny_item_change_response.dart';
import 'package:bungie_api/models/destiny_item_component.dart';
import 'package:bungie_api/models/destiny_item_component_set_ofint32.dart';
import 'package:bungie_api/models/destiny_item_component_set_ofint64.dart';
import 'package:bungie_api/models/destiny_item_component_set_ofuint32.dart';
import 'package:bungie_api/models/destiny_item_crafting_block_bonus_plug_definition.dart';
import 'package:bungie_api/models/destiny_item_crafting_block_definition.dart';
import 'package:bungie_api/models/destiny_item_creation_entry_level_definition.dart';
import 'package:bungie_api/models/destiny_item_gearset_block_definition.dart';
import 'package:bungie_api/models/destiny_item_instance_component.dart';
import 'package:bungie_api/models/destiny_item_instance_energy.dart';
import 'package:bungie_api/models/destiny_item_intrinsic_socket_entry_definition.dart';
import 'package:bungie_api/models/destiny_item_inventory_block_definition.dart';
import 'package:bungie_api/models/destiny_item_investment_stat_definition.dart';
import 'package:bungie_api/models/destiny_item_metric_block_definition.dart';
import 'package:bungie_api/models/destiny_item_objective_block_definition.dart';
import 'package:bungie_api/models/destiny_item_objectives_component.dart';
import 'package:bungie_api/models/destiny_item_peer_view.dart';
import 'package:bungie_api/models/destiny_item_perk_entry_definition.dart';
import 'package:bungie_api/models/destiny_item_perks_component.dart';
import 'package:bungie_api/models/destiny_item_plug.dart';
import 'package:bungie_api/models/destiny_item_plug_base.dart';
import 'package:bungie_api/models/destiny_item_plug_component.dart';
import 'package:bungie_api/models/destiny_item_plug_definition.dart';
import 'package:bungie_api/models/destiny_item_plug_objectives_component.dart';
import 'package:bungie_api/models/destiny_item_preview_block_definition.dart';
import 'package:bungie_api/models/destiny_item_quality_block_definition.dart';
import 'package:bungie_api/models/destiny_item_quantity.dart';
import 'package:bungie_api/models/destiny_item_render_component.dart';
import 'package:bungie_api/models/destiny_item_response.dart';
import 'package:bungie_api/models/destiny_item_reusable_plugs_component.dart';
import 'package:bungie_api/models/destiny_item_sack_block_definition.dart';
import 'package:bungie_api/models/destiny_item_set_action_request.dart';
import 'package:bungie_api/models/destiny_item_set_block_definition.dart';
import 'package:bungie_api/models/destiny_item_set_block_entry_definition.dart';
import 'package:bungie_api/models/destiny_item_socket_block_definition.dart';
import 'package:bungie_api/models/destiny_item_socket_category_definition.dart';
import 'package:bungie_api/models/destiny_item_socket_entry_definition.dart';
import 'package:bungie_api/models/destiny_item_socket_entry_plug_item_definition.dart';
import 'package:bungie_api/models/destiny_item_socket_entry_plug_item_randomized_definition.dart';
import 'package:bungie_api/models/destiny_item_socket_state.dart';
import 'package:bungie_api/models/destiny_item_sockets_component.dart';
import 'package:bungie_api/models/destiny_item_source_block_definition.dart';
import 'package:bungie_api/models/destiny_item_source_definition.dart';
import 'package:bungie_api/models/destiny_item_stat_block_definition.dart';
import 'package:bungie_api/models/destiny_item_state_request.dart';
import 'package:bungie_api/models/destiny_item_stats_component.dart';
import 'package:bungie_api/models/destiny_item_summary_block_definition.dart';
import 'package:bungie_api/models/destiny_item_talent_grid_block_definition.dart';
import 'package:bungie_api/models/destiny_item_talent_grid_component.dart';
import 'package:bungie_api/models/destiny_item_tier_type_definition.dart';
import 'package:bungie_api/models/destiny_item_tier_type_infusion_block.dart';
import 'package:bungie_api/models/destiny_item_tooltip_notification.dart';
import 'package:bungie_api/models/destiny_item_transfer_request.dart';
import 'package:bungie_api/models/destiny_item_translation_block_definition.dart';
import 'package:bungie_api/models/destiny_item_value_block_definition.dart';
import 'package:bungie_api/models/destiny_item_vendor_source_reference.dart';
import 'package:bungie_api/models/destiny_item_version_definition.dart';
import 'package:bungie_api/models/destiny_kiosk_item.dart';
import 'package:bungie_api/models/destiny_kiosks_component.dart';
import 'package:bungie_api/models/destiny_leaderboard.dart';
import 'package:bungie_api/models/destiny_leaderboard_entry.dart';
import 'package:bungie_api/models/destiny_leaderboard_results.dart';
import 'package:bungie_api/models/destiny_linked_graph_definition.dart';
import 'package:bungie_api/models/destiny_linked_graph_entry_definition.dart';
import 'package:bungie_api/models/destiny_linked_profiles_response.dart';
import 'package:bungie_api/models/destiny_location_definition.dart';
import 'package:bungie_api/models/destiny_location_release_definition.dart';
import 'package:bungie_api/models/destiny_lore_definition.dart';
import 'package:bungie_api/models/destiny_manifest.dart';
import 'package:bungie_api/models/destiny_material_requirement.dart';
import 'package:bungie_api/models/destiny_material_requirement_set_definition.dart';
import 'package:bungie_api/models/destiny_medal_tier_definition.dart';
import 'package:bungie_api/models/destiny_metric_component.dart';
import 'package:bungie_api/models/destiny_metric_definition.dart';
import 'package:bungie_api/models/destiny_metrics_component.dart';
import 'package:bungie_api/models/destiny_milestone.dart';
import 'package:bungie_api/models/destiny_milestone_activity.dart';
import 'package:bungie_api/models/destiny_milestone_activity_completion_status.dart';
import 'package:bungie_api/models/destiny_milestone_activity_definition.dart';
import 'package:bungie_api/models/destiny_milestone_activity_phase.dart';
import 'package:bungie_api/models/destiny_milestone_activity_variant.dart';
import 'package:bungie_api/models/destiny_milestone_activity_variant_definition.dart';
import 'package:bungie_api/models/destiny_milestone_challenge_activity.dart';
import 'package:bungie_api/models/destiny_milestone_challenge_activity_definition.dart';
import 'package:bungie_api/models/destiny_milestone_challenge_activity_graph_node_entry.dart';
import 'package:bungie_api/models/destiny_milestone_challenge_activity_phase.dart';
import 'package:bungie_api/models/destiny_milestone_challenge_definition.dart';
import 'package:bungie_api/models/destiny_milestone_content.dart';
import 'package:bungie_api/models/destiny_milestone_content_item_category.dart';
import 'package:bungie_api/models/destiny_milestone_definition.dart';
import 'package:bungie_api/models/destiny_milestone_quest.dart';
import 'package:bungie_api/models/destiny_milestone_quest_definition.dart';
import 'package:bungie_api/models/destiny_milestone_quest_reward_item.dart';
import 'package:bungie_api/models/destiny_milestone_quest_rewards_definition.dart';
import 'package:bungie_api/models/destiny_milestone_reward_category.dart';
import 'package:bungie_api/models/destiny_milestone_reward_category_definition.dart';
import 'package:bungie_api/models/destiny_milestone_reward_entry.dart';
import 'package:bungie_api/models/destiny_milestone_reward_entry_definition.dart';
import 'package:bungie_api/models/destiny_milestone_value_definition.dart';
import 'package:bungie_api/models/destiny_milestone_vendor.dart';
import 'package:bungie_api/models/destiny_milestone_vendor_definition.dart';
import 'package:bungie_api/models/destiny_node_activation_requirement.dart';
import 'package:bungie_api/models/destiny_node_socket_replace_response.dart';
import 'package:bungie_api/models/destiny_node_step_definition.dart';
import 'package:bungie_api/models/destiny_objective_definition.dart';
import 'package:bungie_api/models/destiny_objective_display_properties.dart';
import 'package:bungie_api/models/destiny_objective_perk_entry_definition.dart';
import 'package:bungie_api/models/destiny_objective_progress.dart';
import 'package:bungie_api/models/destiny_objective_stat_entry_definition.dart';
import 'package:bungie_api/models/destiny_parent_item_override.dart';
import 'package:bungie_api/models/destiny_perk_reference.dart';
import 'package:bungie_api/models/destiny_place_definition.dart';
import 'package:bungie_api/models/destiny_platform_silver_component.dart';
import 'package:bungie_api/models/destiny_player.dart';
import 'package:bungie_api/models/destiny_plug_item_crafting_requirements.dart';
import 'package:bungie_api/models/destiny_plug_item_crafting_unlock_requirement.dart';
import 'package:bungie_api/models/destiny_plug_rule_definition.dart';
import 'package:bungie_api/models/destiny_plug_set_definition.dart';
import 'package:bungie_api/models/destiny_plug_sets_component.dart';
import 'package:bungie_api/models/destiny_plug_whitelist_entry_definition.dart';
import 'package:bungie_api/models/destiny_position_definition.dart';
import 'package:bungie_api/models/destiny_post_game_carnage_report_data.dart';
import 'package:bungie_api/models/destiny_post_game_carnage_report_entry.dart';
import 'package:bungie_api/models/destiny_post_game_carnage_report_extended_data.dart';
import 'package:bungie_api/models/destiny_post_game_carnage_report_team_entry.dart';
import 'package:bungie_api/models/destiny_postmaster_transfer_request.dart';
import 'package:bungie_api/models/destiny_power_cap_definition.dart';
import 'package:bungie_api/models/destiny_presentation_child_block.dart';
import 'package:bungie_api/models/destiny_presentation_node_base_definition.dart';
import 'package:bungie_api/models/destiny_presentation_node_child_entry.dart';
import 'package:bungie_api/models/destiny_presentation_node_child_entry_base.dart';
import 'package:bungie_api/models/destiny_presentation_node_children_block.dart';
import 'package:bungie_api/models/destiny_presentation_node_collectible_child_entry.dart';
import 'package:bungie_api/models/destiny_presentation_node_component.dart';
import 'package:bungie_api/models/destiny_presentation_node_craftable_child_entry.dart';
import 'package:bungie_api/models/destiny_presentation_node_definition.dart';
import 'package:bungie_api/models/destiny_presentation_node_metric_child_entry.dart';
import 'package:bungie_api/models/destiny_presentation_node_record_child_entry.dart';
import 'package:bungie_api/models/destiny_presentation_node_requirements_block.dart';
import 'package:bungie_api/models/destiny_presentation_nodes_component.dart';
import 'package:bungie_api/models/destiny_profile_collectibles_component.dart';
import 'package:bungie_api/models/destiny_profile_component.dart';
import 'package:bungie_api/models/destiny_profile_progression_component.dart';
import 'package:bungie_api/models/destiny_profile_records_component.dart';
import 'package:bungie_api/models/destiny_profile_response.dart';
import 'package:bungie_api/models/destiny_profile_transitory_component.dart';
import 'package:bungie_api/models/destiny_profile_transitory_current_activity.dart';
import 'package:bungie_api/models/destiny_profile_transitory_joinability.dart';
import 'package:bungie_api/models/destiny_profile_transitory_party_member.dart';
import 'package:bungie_api/models/destiny_profile_transitory_tracking_entry.dart';
import 'package:bungie_api/models/destiny_profile_user_info_card.dart';
import 'package:bungie_api/models/destiny_progression.dart';
import 'package:bungie_api/models/destiny_progression_definition.dart';
import 'package:bungie_api/models/destiny_progression_display_properties_definition.dart';
import 'package:bungie_api/models/destiny_progression_level_requirement_definition.dart';
import 'package:bungie_api/models/destiny_progression_mapping_definition.dart';
import 'package:bungie_api/models/destiny_progression_reset_entry.dart';
import 'package:bungie_api/models/destiny_progression_reward_definition.dart';
import 'package:bungie_api/models/destiny_progression_reward_item_quantity.dart';
import 'package:bungie_api/models/destiny_progression_step_definition.dart';
import 'package:bungie_api/models/destiny_public_activity_status.dart';
import 'package:bungie_api/models/destiny_public_milestone.dart';
import 'package:bungie_api/models/destiny_public_milestone_activity.dart';
import 'package:bungie_api/models/destiny_public_milestone_activity_variant.dart';
import 'package:bungie_api/models/destiny_public_milestone_challenge.dart';
import 'package:bungie_api/models/destiny_public_milestone_challenge_activity.dart';
import 'package:bungie_api/models/destiny_public_milestone_quest.dart';
import 'package:bungie_api/models/destiny_public_milestone_vendor.dart';
import 'package:bungie_api/models/destiny_public_vendor_component.dart';
import 'package:bungie_api/models/destiny_public_vendor_sale_item_component.dart';
import 'package:bungie_api/models/destiny_public_vendors_response.dart';
import 'package:bungie_api/models/destiny_quest_status.dart';
import 'package:bungie_api/models/destiny_race_definition.dart';
import 'package:bungie_api/models/destiny_record_completion_block.dart';
import 'package:bungie_api/models/destiny_record_component.dart';
import 'package:bungie_api/models/destiny_record_definition.dart';
import 'package:bungie_api/models/destiny_record_expiration_block.dart';
import 'package:bungie_api/models/destiny_record_interval_block.dart';
import 'package:bungie_api/models/destiny_record_interval_objective.dart';
import 'package:bungie_api/models/destiny_record_interval_rewards.dart';
import 'package:bungie_api/models/destiny_record_title_block.dart';
import 'package:bungie_api/models/destiny_records_component.dart';
import 'package:bungie_api/models/destiny_report_offense_pgcr_request.dart';
import 'package:bungie_api/models/destiny_report_reason_category_definition.dart';
import 'package:bungie_api/models/destiny_report_reason_definition.dart';
import 'package:bungie_api/models/destiny_reward_source_definition.dart';
import 'package:bungie_api/models/destiny_sandbox_perk_definition.dart';
import 'package:bungie_api/models/destiny_scored_presentation_node_base_definition.dart';
import 'package:bungie_api/models/destiny_season_definition.dart';
import 'package:bungie_api/models/destiny_season_pass_definition.dart';
import 'package:bungie_api/models/destiny_season_preview_definition.dart';
import 'package:bungie_api/models/destiny_season_preview_image_definition.dart';
import 'package:bungie_api/models/destiny_socket_category_definition.dart';
import 'package:bungie_api/models/destiny_socket_type_definition.dart';
import 'package:bungie_api/models/destiny_socket_type_scalar_material_requirement_entry.dart';
import 'package:bungie_api/models/destiny_stat.dart';
import 'package:bungie_api/models/destiny_stat_definition.dart';
import 'package:bungie_api/models/destiny_stat_display_definition.dart';
import 'package:bungie_api/models/destiny_stat_group_definition.dart';
import 'package:bungie_api/models/destiny_stat_override_definition.dart';
import 'package:bungie_api/models/destiny_string_variables_component.dart';
import 'package:bungie_api/models/destiny_talent_exclusive_group.dart';
import 'package:bungie_api/models/destiny_talent_grid_definition.dart';
import 'package:bungie_api/models/destiny_talent_node.dart';
import 'package:bungie_api/models/destiny_talent_node_category.dart';
import 'package:bungie_api/models/destiny_talent_node_definition.dart';
import 'package:bungie_api/models/destiny_talent_node_exclusive_set_definition.dart';
import 'package:bungie_api/models/destiny_talent_node_stat_block.dart';
import 'package:bungie_api/models/destiny_talent_node_step_groups.dart';
import 'package:bungie_api/models/destiny_trait_category_definition.dart';
import 'package:bungie_api/models/destiny_trait_definition.dart';
import 'package:bungie_api/models/destiny_unlock_definition.dart';
import 'package:bungie_api/models/destiny_unlock_expression_definition.dart';
import 'package:bungie_api/models/destiny_unlock_status.dart';
import 'package:bungie_api/models/destiny_unlock_value_definition.dart';
import 'package:bungie_api/models/destiny_vendor_accepted_item_definition.dart';
import 'package:bungie_api/models/destiny_vendor_action_definition.dart';
import 'package:bungie_api/models/destiny_vendor_base_component.dart';
import 'package:bungie_api/models/destiny_vendor_categories_component.dart';
import 'package:bungie_api/models/destiny_vendor_category.dart';
import 'package:bungie_api/models/destiny_vendor_category_entry_definition.dart';
import 'package:bungie_api/models/destiny_vendor_category_overlay_definition.dart';
import 'package:bungie_api/models/destiny_vendor_component.dart';
import 'package:bungie_api/models/destiny_vendor_definition.dart';
import 'package:bungie_api/models/destiny_vendor_display_properties_definition.dart';
import 'package:bungie_api/models/destiny_vendor_group.dart';
import 'package:bungie_api/models/destiny_vendor_group_component.dart';
import 'package:bungie_api/models/destiny_vendor_group_definition.dart';
import 'package:bungie_api/models/destiny_vendor_group_reference.dart';
import 'package:bungie_api/models/destiny_vendor_interaction_definition.dart';
import 'package:bungie_api/models/destiny_vendor_interaction_reply_definition.dart';
import 'package:bungie_api/models/destiny_vendor_interaction_sack_entry_definition.dart';
import 'package:bungie_api/models/destiny_vendor_inventory_flyout_bucket_definition.dart';
import 'package:bungie_api/models/destiny_vendor_inventory_flyout_definition.dart';
import 'package:bungie_api/models/destiny_vendor_item_definition.dart';
import 'package:bungie_api/models/destiny_vendor_item_quantity.dart';
import 'package:bungie_api/models/destiny_vendor_item_socket_override.dart';
import 'package:bungie_api/models/destiny_vendor_location_definition.dart';
import 'package:bungie_api/models/destiny_vendor_receipt.dart';
import 'package:bungie_api/models/destiny_vendor_receipts_component.dart';
import 'package:bungie_api/models/destiny_vendor_requirement_display_entry_definition.dart';
import 'package:bungie_api/models/destiny_vendor_response.dart';
import 'package:bungie_api/models/destiny_vendor_sale_item_action_block_definition.dart';
import 'package:bungie_api/models/destiny_vendor_sale_item_base_component.dart';
import 'package:bungie_api/models/destiny_vendor_sale_item_component.dart';
import 'package:bungie_api/models/destiny_vendor_sale_item_set_component_of_destiny_public_vendor_sale_item_component.dart';
import 'package:bungie_api/models/destiny_vendor_sale_item_set_component_of_destiny_vendor_sale_item_component.dart';
import 'package:bungie_api/models/destiny_vendor_service_definition.dart';
import 'package:bungie_api/models/destiny_vendors_response.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint32_and_destiny_item_instance_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint32_and_destiny_item_objectives_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint32_and_destiny_item_perks_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint32_and_destiny_item_plug_objectives_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint32_and_destiny_item_render_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint32_and_destiny_item_reusable_plugs_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint32_and_destiny_item_sockets_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint32_and_destiny_item_stats_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint32_and_destiny_item_talent_grid_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint32_and_destiny_vendor_sale_item_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_character_activities_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_character_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_character_progression_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_character_records_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_character_render_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_collectibles_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_craftables_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_currencies_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_inventory_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_item_instance_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_item_objectives_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_item_perks_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_item_plug_objectives_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_item_render_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_item_reusable_plugs_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_item_sockets_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_item_stats_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_item_talent_grid_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_kiosks_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_plug_sets_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_presentation_nodes_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofint64_and_destiny_string_variables_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_destiny_item_instance_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_destiny_item_objectives_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_destiny_item_perks_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_destiny_item_plug_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_destiny_item_plug_objectives_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_destiny_item_render_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_destiny_item_reusable_plugs_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_destiny_item_sockets_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_destiny_item_stats_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_destiny_item_talent_grid_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_destiny_public_vendor_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_destiny_vendor_categories_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_destiny_vendor_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_personal_destiny_vendor_sale_item_set_component.dart';
import 'package:bungie_api/models/dictionary_component_response_ofuint32_and_public_destiny_vendor_sale_item_set_component.dart';
import 'package:bungie_api/models/dye_reference.dart';
import 'package:bungie_api/models/email_opt_in_definition.dart';
import 'package:bungie_api/models/email_setting_localization.dart';
import 'package:bungie_api/models/email_setting_subscription_localization.dart';
import 'package:bungie_api/models/email_settings.dart';
import 'package:bungie_api/models/email_subscription_definition.dart';
import 'package:bungie_api/models/email_view_definition.dart';
import 'package:bungie_api/models/email_view_definition_setting.dart';
import 'package:bungie_api/models/entity_action_result.dart';
import 'package:bungie_api/models/exact_search_request.dart';
import 'package:bungie_api/models/fireteam_member.dart';
import 'package:bungie_api/models/fireteam_response.dart';
import 'package:bungie_api/models/fireteam_summary.dart';
import 'package:bungie_api/models/fireteam_user_info_card.dart';
import 'package:bungie_api/models/forum_recruitment_detail.dart';
import 'package:bungie_api/models/gear_asset_data_base_definition.dart';
import 'package:bungie_api/models/general_user.dart';
import 'package:bungie_api/models/get_credential_types_for_account_response.dart';
import 'package:bungie_api/models/get_groups_for_member_response.dart';
import 'package:bungie_api/models/global_alert.dart';
import 'package:bungie_api/models/group_application_list_request.dart';
import 'package:bungie_api/models/group_application_request.dart';
import 'package:bungie_api/models/group_application_response.dart';
import 'package:bungie_api/models/group_ban.dart';
import 'package:bungie_api/models/group_ban_request.dart';
import 'package:bungie_api/models/group_edit_action.dart';
import 'package:bungie_api/models/group_features.dart';
import 'package:bungie_api/models/group_member.dart';
import 'package:bungie_api/models/group_member_application.dart';
import 'package:bungie_api/models/group_member_leave_result.dart';
import 'package:bungie_api/models/group_membership.dart';
import 'package:bungie_api/models/group_membership_base.dart';
import 'package:bungie_api/models/group_membership_search_response.dart';
import 'package:bungie_api/models/group_name_search_request.dart';
import 'package:bungie_api/models/group_optional_conversation.dart';
import 'package:bungie_api/models/group_optional_conversation_add_request.dart';
import 'package:bungie_api/models/group_optional_conversation_edit_request.dart';
import 'package:bungie_api/models/group_options_edit_action.dart';
import 'package:bungie_api/models/group_potential_member.dart';
import 'package:bungie_api/models/group_potential_membership.dart';
import 'package:bungie_api/models/group_potential_membership_search_response.dart';
import 'package:bungie_api/models/group_query.dart';
import 'package:bungie_api/models/group_response.dart';
import 'package:bungie_api/models/group_search_response.dart';
import 'package:bungie_api/models/group_theme.dart';
import 'package:bungie_api/models/group_user_base.dart';
import 'package:bungie_api/models/group_user_info_card.dart';
import 'package:bungie_api/models/group_v2.dart';
import 'package:bungie_api/models/group_v2_card.dart';
import 'package:bungie_api/models/group_v2_clan_info.dart';
import 'package:bungie_api/models/group_v2_clan_info_and_investment.dart';
import 'package:bungie_api/models/hard_linked_user_membership.dart';
import 'package:bungie_api/models/hyperlink_reference.dart';
import 'package:bungie_api/models/ignore_response.dart';
import 'package:bungie_api/models/image_pyramid_entry.dart';
import 'package:bungie_api/models/interpolation_point.dart';
import 'package:bungie_api/models/interpolation_point_float.dart';
import 'package:bungie_api/models/inventory_changed_response.dart';
import 'package:bungie_api/models/paged_query.dart';
import 'package:bungie_api/models/partner_offer_claim_request.dart';
import 'package:bungie_api/models/partner_offer_history_response.dart';
import 'package:bungie_api/models/partner_offer_sku_history_response.dart';
import 'package:bungie_api/models/personal_destiny_vendor_sale_item_set_component.dart';
import 'package:bungie_api/models/platform_friend.dart';
import 'package:bungie_api/models/platform_friend_response.dart';
import 'package:bungie_api/models/poll_response.dart';
import 'package:bungie_api/models/poll_result.dart';
import 'package:bungie_api/models/post_response.dart';
import 'package:bungie_api/models/post_search_response.dart';
import 'package:bungie_api/models/public_destiny_vendor_sale_item_set_component.dart';
import 'package:bungie_api/models/schema_record_state_block.dart';
import 'package:bungie_api/models/search_result.dart';
import 'package:bungie_api/models/search_result_of_content_item_public_contract.dart';
import 'package:bungie_api/models/search_result_of_destiny_entity_search_result_item.dart';
import 'package:bungie_api/models/search_result_of_fireteam_response.dart';
import 'package:bungie_api/models/search_result_of_fireteam_summary.dart';
import 'package:bungie_api/models/search_result_of_group_ban.dart';
import 'package:bungie_api/models/search_result_of_group_member.dart';
import 'package:bungie_api/models/search_result_of_group_member_application.dart';
import 'package:bungie_api/models/search_result_of_group_membership.dart';
import 'package:bungie_api/models/search_result_of_group_potential_membership.dart';
import 'package:bungie_api/models/search_result_of_group_v2_card.dart';
import 'package:bungie_api/models/search_result_of_post_response.dart';
import 'package:bungie_api/models/search_result_of_trending_entry.dart';
import 'package:bungie_api/models/series.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_character_activities_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_character_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_character_progression_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_character_records_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_character_render_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_collectibles_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_currencies_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_inventory_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_item_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_item_instance_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_item_objectives_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_item_perks_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_item_plug_objectives_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_item_render_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_item_reusable_plugs_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_item_sockets_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_item_stats_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_item_talent_grid_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_kiosks_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_metrics_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_platform_silver_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_plug_sets_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_presentation_nodes_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_profile_collectibles_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_profile_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_profile_progression_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_profile_records_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_profile_transitory_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_string_variables_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_vendor_categories_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_vendor_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_vendor_group_component.dart';
import 'package:bungie_api/models/single_component_response_of_destiny_vendor_receipts_component.dart';
import 'package:bungie_api/models/stream_info.dart';
import 'package:bungie_api/models/tag_metadata_definition.dart';
import 'package:bungie_api/models/tag_metadata_item.dart';
import 'package:bungie_api/models/tag_response.dart';
import 'package:bungie_api/models/trending_categories.dart';
import 'package:bungie_api/models/trending_category.dart';
import 'package:bungie_api/models/trending_detail.dart';
import 'package:bungie_api/models/trending_entry.dart';
import 'package:bungie_api/models/trending_entry_community_creation.dart';
import 'package:bungie_api/models/trending_entry_destiny_activity.dart';
import 'package:bungie_api/models/trending_entry_destiny_item.dart';
import 'package:bungie_api/models/trending_entry_destiny_ritual.dart';
import 'package:bungie_api/models/trending_entry_news.dart';
import 'package:bungie_api/models/trending_entry_support_article.dart';
import 'package:bungie_api/models/user_info_card.dart';
import 'package:bungie_api/models/user_membership.dart';
import 'package:bungie_api/models/user_membership_data.dart';
import 'package:bungie_api/models/user_search_prefix_request.dart';
import 'package:bungie_api/models/user_search_response.dart';
import 'package:bungie_api/models/user_search_response_detail.dart';
import 'package:bungie_api/models/user_theme.dart';
import 'package:bungie_api/models/user_to_user_context.dart';
import 'package:bungie_api/queries.dart';
import 'package:bungie_api/responses/api_usage_response.dart';
import 'package:bungie_api/responses/awa_authorization_result_response.dart';
import 'package:bungie_api/responses/awa_initialize_response_response.dart';
import 'package:bungie_api/responses/boolean_response.dart';
import 'package:bungie_api/responses/bungie_friend_list_response_response.dart';
import 'package:bungie_api/responses/bungie_friend_request_list_response_response.dart';
import 'package:bungie_api/responses/cedictionary_ofstring_andstring_response.dart';
import 'package:bungie_api/responses/celist_of_forum_recruitment_detail_response.dart';
import 'package:bungie_api/responses/celist_of_global_alert_response.dart';
import 'package:bungie_api/responses/celist_of_group_optional_conversation_response.dart';
import 'package:bungie_api/responses/celist_of_partner_offer_sku_history_response_response.dart';
import 'package:bungie_api/responses/clan_banner_source_response.dart';
import 'package:bungie_api/responses/content_item_public_contract_response.dart';
import 'package:bungie_api/responses/content_type_description_response.dart';
import 'package:bungie_api/responses/core_settings_configuration_response.dart';
import 'package:bungie_api/responses/destiny_activity_history_results_response.dart';
import 'package:bungie_api/responses/destiny_aggregate_activity_results_response.dart';
import 'package:bungie_api/responses/destiny_character_response_response.dart';
import 'package:bungie_api/responses/destiny_collectible_node_detail_response_response.dart';
import 'package:bungie_api/responses/destiny_definition_response.dart';
import 'package:bungie_api/responses/destiny_entity_search_result_response.dart';
import 'package:bungie_api/responses/destiny_equip_item_results_response.dart';
import 'package:bungie_api/responses/destiny_historical_stats_account_result_response.dart';
import 'package:bungie_api/responses/destiny_historical_stats_results_response.dart';
import 'package:bungie_api/responses/destiny_historical_weapon_stats_data_response.dart';
import 'package:bungie_api/responses/destiny_item_change_response_response.dart';
import 'package:bungie_api/responses/destiny_item_response_response.dart';
import 'package:bungie_api/responses/destiny_leaderboard_results_response.dart';
import 'package:bungie_api/responses/destiny_linked_profiles_response_response.dart';
import 'package:bungie_api/responses/destiny_manifest_response.dart';
import 'package:bungie_api/responses/destiny_milestone_content_response.dart';
import 'package:bungie_api/responses/destiny_milestone_response.dart';
import 'package:bungie_api/responses/destiny_post_game_carnage_report_data_response.dart';
import 'package:bungie_api/responses/destiny_profile_response_response.dart';
import 'package:bungie_api/responses/destiny_public_vendors_response_response.dart';
import 'package:bungie_api/responses/destiny_vendor_response_response.dart';
import 'package:bungie_api/responses/destiny_vendors_response_response.dart';
import 'package:bungie_api/responses/dictionary_ofint32_andstring_response.dart';
import 'package:bungie_api/responses/dictionary_ofstring_and_core_system_response.dart';
import 'package:bungie_api/responses/dictionary_ofuint32_and_destiny_public_milestone_response.dart';
import 'package:bungie_api/responses/fireteam_response_response.dart';
import 'package:bungie_api/responses/general_user_response.dart';
import 'package:bungie_api/responses/get_groups_for_member_response_response.dart';
import 'package:bungie_api/responses/group_application_response_response.dart';
import 'package:bungie_api/responses/group_member_leave_result_response.dart';
import 'package:bungie_api/responses/group_membership_search_response_response.dart';
import 'package:bungie_api/responses/group_potential_membership_search_response_response.dart';
import 'package:bungie_api/responses/group_response_response.dart';
import 'package:bungie_api/responses/group_search_response_response.dart';
import 'package:bungie_api/responses/hard_linked_user_membership_response.dart';
import 'package:bungie_api/responses/ienumerable_of_application_response.dart';
import 'package:bungie_api/responses/ienumerable_of_user_info_card_response.dart';
import 'package:bungie_api/responses/int32_response.dart';
import 'package:bungie_api/responses/int64_response.dart';
import 'package:bungie_api/responses/iread_only_collection_of_content_item_public_contract_response.dart';
import 'package:bungie_api/responses/list_of_destiny_clan_aggregate_stat_response.dart';
import 'package:bungie_api/responses/list_of_entity_action_result_response.dart';
import 'package:bungie_api/responses/list_of_get_credential_types_for_account_response_response.dart';
import 'package:bungie_api/responses/list_of_group_theme_response.dart';
import 'package:bungie_api/responses/list_of_group_v2_card_response.dart';
import 'package:bungie_api/responses/list_of_tag_response_response.dart';
import 'package:bungie_api/responses/list_of_user_theme_response.dart';
import 'package:bungie_api/responses/platform_friend_response_response.dart';
import 'package:bungie_api/responses/post_search_response_response.dart';
import 'package:bungie_api/responses/read_only_dictionary_ofstring_and_destiny_historical_stats_definition_response.dart';
import 'package:bungie_api/responses/search_result_of_content_item_public_contract_response.dart';
import 'package:bungie_api/responses/search_result_of_fireteam_response_response.dart';
import 'package:bungie_api/responses/search_result_of_fireteam_summary_response.dart';
import 'package:bungie_api/responses/search_result_of_group_ban_response.dart';
import 'package:bungie_api/responses/search_result_of_group_member_application_response.dart';
import 'package:bungie_api/responses/search_result_of_group_member_response.dart';
import 'package:bungie_api/responses/search_result_of_trending_entry_response.dart';
import 'package:bungie_api/responses/trending_categories_response.dart';
import 'package:bungie_api/responses/trending_detail_response.dart';
import 'package:bungie_api/responses/user_membership_data_response.dart';
import 'package:bungie_api/responses/user_search_response_response.dart';
import 'package:bungie_api/settings.dart';
import 'package:bungie_api/social.dart';
import 'package:bungie_api/tags.dart';
import 'package:bungie_api/tokens.dart';
import 'package:bungie_api/trending.dart';
import 'package:bungie_api/user.dart';
import 'package:bungie_api/usersystemoverrides.dart';
Author: LittleLightForDestiny
Source Code: https://github.com/LittleLightForDestiny/bungie-api-dart
License: MIT license
1656745987
KARTE Notification for Flutter
A Flutter plugin to use the KARTE Notification API, for both Android & iOS. KARTE Notification package provides a simple API for push notification.
The developer guide is located at
Flutter KARTE Notification package is published under the Apache 2.0 License.
Your use of KARTE is governed by the KARTE Terms of Use.
Run this command:
With Flutter:
$ flutter pub add karte_notification
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
karte_notification: ^1.1.0
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:karte_notification/karte_notification.dart';
import 'dart:async';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:karte_core/karte_core.dart';
import 'package:karte_notification/karte_notification.dart' as krt;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
Future<dynamic> myBackgroundMessageHandler(RemoteMessage message) async {
// Called when received notification on background only Android
print('myBackgroundMessageHandler $message');
var karteNotification = await krt.Notification.create(message);
print("karte notification: $karteNotification");
if (karteNotification != null) {
karteNotification.handleForAndroid();
}
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _homeScreenText = "Waiting for token...";
String _logText = "";
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
void updateState({String? log, String? token}) {
if (!mounted) return;
setState(() {
if (log != null) _logText += log;
if (token != null) _homeScreenText = "Push Messaging token: $token";
});
}
void checkInitialMessage() async {
RemoteMessage? message =
await FirebaseMessaging.instance.getInitialMessage();
// Called when app launch by tap notification on iOS
print("checkInitialMessage: $message");
updateState(log: "\nonLaunch");
if (message == null) return;
var karteNotification = await krt.Notification.create(message);
print("karte notification: $karteNotification");
if (karteNotification != null) {
karteNotification.handleForIOS();
}
}
@override
void initState() {
super.initState();
checkInitialMessage();
FirebaseMessaging.onBackgroundMessage(myBackgroundMessageHandler);
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
// Called when received notification on foreground
print("onMessage: $message");
updateState(log: "\nonMessage");
var karteNotification = await krt.Notification.create(message);
print("karte notification: $karteNotification");
if (karteNotification != null) {
karteNotification.handleForAndroid();
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
// Called when app resume by tap notification on iOS
print("onMessageOpenedApp: $message");
updateState(log: "\nonMessageOpenedApp");
var karteNotification = await krt.Notification.create(message);
print("karte notification: $karteNotification");
if (karteNotification != null) {
karteNotification.handleForIOS();
}
});
_firebaseMessaging
.requestPermission(
alert: true, badge: true, provisional: true, sound: true)
.then((NotificationSettings value) {
print("Settings registered: $value");
});
_firebaseMessaging.onTokenRefresh.listen((String token) {
print("onTokenRefreshed: $token");
krt.Notification.registerFCMToken(token);
updateState(token: token);
});
_firebaseMessaging.getToken().then((String? token) {
if (token == null) return;
krt.Notification.registerFCMToken(token);
updateState(token: token);
print(_homeScreenText);
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('KARTE Notification example app'),
),
body: Center(
child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_homeScreenText),
ElevatedButton(
onPressed: () {
Tracker.view("push_text");
},
child: Text("View"),
),
Text(_logText),
]),
),
),
);
}
}
Download Details:
Author: plaidev
Source Code: https://github.com/plaidev/karte-flutter
1656745200
This repo contains Flutter plugins maintained by the flutter-tizen team. We're in process of adding Tizen platform support to existing first and third-party plugins on pub.dev based on their popularity. If the plugin you're looking for isn't implemented for Tizen yet, consider filing an issue or creating a package by yourself. (We welcome your pull requests!)
To build Flutter applications with plugins, use the flutter-tizen tool.
For how to extend existing plugins for Tizen, see Writing custom platform-specific code and Federated plugins from the Flutter docs. If the original plugin uses the federated plugins approach, you can implement its platform interface either in Dart (inheriting directly) or C++ (using a fallback method channel).
The "non-endorsed" status means that the plugin is not endorsed by the original author. In such case, you must set both foobar
and foobar_tizen
package dependencies in pubspec.yaml
file to achieve full functionality.
Package name | Watch | Watch emulator | TV | TV emulator | Remarks |
---|---|---|---|---|---|
audioplayers_tizen | ✔️ | ✔️ | ⚠️ | ⚠️ | Functional limitations (see README) |
battery_plus_tizen | ✔️ | ✔️ | ❌ | ❌ | No battery |
camera_tizen | ❌ | ❌ | ❌ | ❌ | No camera |
connectivity_plus_tizen | ✔️ | ⚠️ | ✔️ | ✔️ | Returns incorrect connection status |
device_info_plus_tizen | ✔️ | ✔️ | ✔️ | ✔️ | |
flutter_tts_tizen | ✔️ | ✔️ | ✔️ | ✔️ | |
geolocator_tizen | ✔️ | ✔️ | ❌ | ❌ | Not applicable for TV |
google_maps_flutter_tizen | ❌ | ❌ | ✔️ | ❌ | Dependent library unavailable |
image_picker_tizen | ⚠️ | ❌ | ❌ | ❌ | No camera No file manager app |
integration_test_tizen | ✔️ | ✔️ | ✔️ | ✔️ | |
messageport_tizen | ✔️ | ✔️ | ✔️ | ✔️ | |
network_info_plus_tizen | ✔️ | ❌ | ✔️ | ❌ | API not supported on emulator |
package_info_plus_tizen | ✔️ | ✔️ | ✔️ | ✔️ | |
path_provider_tizen | ✔️ | ✔️ | ✔️ | ✔️ | |
permission_handler_tizen | ✔️ | ✔️ | ⚠️ | ⚠️ | Not applicable for TV |
sensors_plus_tizen | ✔️ | ✔️ | ❌ | ❌ | No sensor hardware |
share_plus_tizen | ⚠️ | ⚠️ | ❌ | ❌ | No SMS or e-mail app |
shared_preferences_tizen | ✔️ | ✔️ | ✔️ | ✔️ | |
sqflite_tizen | ✔️ | ✔️ | ✔️ | ✔️ | |
tizen_app_control | ✔️ | ✔️ | ✔️ | ✔️ | |
tizen_app_manager | ✔️ | ✔️ | ✔️ | ✔️ | |
tizen_audio_manager | ✔️ | ✔️ | ✔️ | ✔️ | |
tizen_log | ✔️ | ✔️ | ❌ | ❌ | Not applicable for TV |
tizen_notification | ❌ | ✔️ | ✔️ | ✔️ | API not supported |
tizen_package_manager | ✔️ | ✔️ | ✔️ | ✔️ | |
url_launcher_tizen | ✔️ | ❌ | ✔️ | ❌ | No browser app |
video_player_tizen | ✔️ | ✔️ | ⚠️ | ❌ | Functional limitations (see README) TV emulator issue |
wakelock_tizen | ✔️ | ✔️ | ❌ | ❌ | Cannot override system display setting |
wearable_rotary | ✔️ | ✔️ | ❌ | ❌ | Not applicable for TV |
webview_flutter_tizen | ❌ | ❌ | ✔️ | ❌ | Dependent library unavailable |
The battery
plugin has been replaced by the Flutter Community Plus Plugins version, battery_plus
. Consider migrating to battery_plus
and its Tizen implementation battery_plus_tizen
.
The Tizen implementation of battery
.
This package is not an endorsed implementation of battery
. Therefore, you have to include battery_tizen
alongside battery
as dependencies in your pubspec.yaml
file.
dependencies:
battery: ^2.0.1
battery_tizen: ^2.0.2
Then you can import battery
in your Dart code:
import 'package:battery/battery.dart';
For detailed usage, see https://pub.dev/packages/battery#usage.
Run this command:
With Dart:
$ dart pub add battery_tizen
With Flutter:
$ flutter pub add battery_tizen
This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get
):
dependencies:
battery_tizen: ^2.0.2
Alternatively, your editor might support dart pub get
or flutter pub get
. Check the docs for your editor to learn more.
example/lib/main.dart
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:battery/battery.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final Battery _battery = Battery();
BatteryState? _batteryState;
late StreamSubscription<BatteryState> _batteryStateSubscription;
@override
void initState() {
super.initState();
_batteryStateSubscription =
_battery.onBatteryStateChanged.listen((BatteryState state) {
setState(() {
_batteryState = state;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Text('$_batteryState'),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.battery_unknown),
onPressed: () async {
final int batteryLevel = await _battery.batteryLevel;
// ignore: unawaited_futures
showDialog<void>(
context: context,
builder: (_) => AlertDialog(
content: Text('Battery: $batteryLevel%'),
actions: <Widget>[
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.pop(context);
},
)
],
),
);
},
),
);
}
@override
void dispose() {
super.dispose();
if (_batteryStateSubscription != null) {
_batteryStateSubscription.cancel();
}
}
}
Author: flutter-tizen
Source code: https://github.com/flutter-tizen/plugins
License:
1656745200
High-level APIs for Amazon Web Services (AWS) in Dart
Generated sources are checked into the repository. To generate the sources, run the following command at the root of the generator
folder:
dart bin/generate.dart generate
All commands in generate.dart
has the --help
command available for more information on usage.
TODO
Run this command:
With Dart:
$ dart pub add aws_machinelearning_api
With Flutter:
$ flutter pub add aws_machinelearning_api
This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get
):
dependencies:
aws_machinelearning_api: ^1.2.0
Alternatively, your editor might support dart pub get
or flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:aws_machinelearning_api/machinelearning-2014-12-12.dart';
example/README.md
import 'package:aws_machinelearning_api/machinelearning-2014-12-12.dart';
void main() {
final service = MachineLearning(region: 'eu-west-1');
// See documentation on how to use MachineLearning
}
Author: agilord
Source code: https://github.com/agilord/aws_client
License:
1656744485
Flutter is one of Google’s solutions to cross-platform development. While it is fairly new on the scene, its feature set makes it an instant competitor in this space.
It compiles your app down to native code that runs on iOS or Android, resulting in incredible end-user performance and frame rates. It supports stateful hot reloading during development, meaning you can make changes to your code and watch them get applied on your emulator or physical device with no need to restart your app or lose your app state.
Flutter’s primary focus has been iOS and Android. With the 1.9 release, web support has been added as a technical preview. It is still in its early days, and it may not be production-ready just yet, but it is certainly exciting and promising. Minimal changes are required to take an existing Flutter app and compile it into an HTML, CSS, and JS bundle, as you will soon see.
Flutter web apps can run on any web server. So why would you want to host your Flutter web app on a Node.js server? Well, to be honest, for many of the same reasons that you’d choose Node.js for your other web apps and APIs: it is incredibly good at servicing large volumes of simple requests, you can code your front end and back end in JavaScript, and so on.
You might already have a Node.js API that serves data to your Flutter iOS or Android apps. Compiling your Flutter app as a web app and hosting it on your existing Node.js server might be a logical extension to your current solution, with no need to add additional hosting costs to the equation.
It’s time to dive into the code and see Flutter web in action. In order to follow along with the example, you will need the following tools:
Flutter has fantastic developer documentation. If this is your first time developing a Flutter app.
You will have the opportunity to choose which editor you want to develop in. The examples and instructions in this article are based on Visual Studio Code, but you should still be able to follow along if you choose to use Android Studio instead.
A Node.js 12 server is required to run the web version of the Flutter weather app as well as the back-end weather API.
In order to demonstrate how to add web support to an existing Flutter app, we will start with a simple weather app that has been tested on Android 10 (API level 29).
The weather app allows the user to view the current weather for a predefined list of cities. Weather data is retrieved from a back-end server running on Node.js.
Clone the source code for the weather app and server from GitHub:
Tip: The
weather-app-nodejs-server
repository has aflutter-web-support
branch that contains the completed version of the app copied to the server with Flutter web support enabled.
It is best to clone both repositories beside each other in the same parent folder. The contents of the weather_app_flutter
repository will be built and copied to a folder within the weather-app-nodejs-server
repository.
Open the weather_app_flutter
repository in your editor. Let’s take a closer look at the main.dart
file. It contains the scaffolding and widgets that make up the app’s user interface. The Home
widget class has a fetchWeatherData
function that calls the back-end weather API to retrieve data and update the widget’s state:
fetchWeatherData({String location}) async {
var url = WEATHER_API_URL + location;
final response = await http.get(url);
if (response.statusCode == 200) {
var jsonResponse = convert.jsonDecode(response.body);
setState(() {
this._weatherData = WeatherData(
jsonResponse\['weather'\]['location'],
jsonResponse\['weather'\]['temperature'],
jsonResponse\['weather'\]['weatherDescription'],
);
this._apiError = null;
});
} else {
setState(() {
this._apiError =
'Unable to retrieve weather data from API (HTTP ${response.statusCode})';
});
}
}
The fetchWeatherData
function uses Dart’s http
package to connect to the server over HTTP. There are other Dart packages that you could use, but this is the officially recommended package if you plan on adding web support to your Flutter app.
Also make note of the WEATHER_API_URL
constant. Update the value of this constant before running the app so that it can connect to the API running on your local Node.js server. The URL must contain your machine’s hostname. A localhost
URL will not be accessible to the Android emulator or physical device.
Open up the weather-app-nodejs-server
repository in your editor.
There are a few important files and folders to review:
public/api-test.html
file can be used to quickly test that your server is working as expected after startup (e.g., http://localhost:3000/api-test.html
)routes/weather.js
file contains a simple GET API that accepts a path parameter and returns weather data (e.g., http://localhost:3000/api/weather/londonon
)public-flutter
folder is where you will copy the compiled web version of the weather app. The Node.js server is set up to serve files from this directory to the root context (e.g., http://localhost:3000
)Since web support is still a technical preview, you need the latest in-development version of Flutter, also referred to as the master channel. In the root folder of the weather_app_flutter
repository, run the following commands:
flutter channel master
flutter upgrade
Tip : You may encounter an “Unknown operating system. Cannot install Dart SDK.” error on Windows when running Flutter commands in a bash shell in Visual Studio Code. Try running the commands in a normal Windows command shell.
The upgrade process may take a few minutes. Next, you will need to enable web support in your Flutter installation so that it is available to this and other apps you develop on this workstation:
flutter config --enable-web
flutter devices
Once web support is enabled, you will see a new Chrome device in the device list. Restart Visual Studio Code after running these commands to refresh the device list menu if you don’t see Chrome in that list yet.
To add web support to the weather app, you need to run this command in the top-level folder of the weather_flutter_app
repository:
flutter create .
The create
command will make a few modifications to the app, which you can see in this commit. The most notable change is the addition of a web
subfolder that contains an index.html
:
Start the Node.js server by running this command in the root of the weather-app-nodejs-server
repository:
npm start
Select Chrome from the device list in Visual Studio Code and then start the debugging. Alternatively, you can run the following flutter command:
flutter run -d chrome
The first time you start the app in Chrome may take a little longer while Flutter downloads additional dependencies on the fly. Chrome will eventually open, and you will see the weather app running in the browser. Some of the styling will be slightly different than what you saw on the emulator or physical device.
At this point, you will notice that the app is not displaying any data from the weather API. If you open Chrome DevTools, you will see a cross-origin resource sharing error.
The browser is not allowing the request to be made from the Flutter web server to the Node.js server since they are running on different ports. You could solve this problem by enabling cross-origin resource sharing on the server or installing a Chrome plugin to disable CORS.
We are going to ignore the error for now since in the next step we will run the pre-compiled Flutter web code directly on the Node.js server, thus eliminating the cross-origin requests altogether.
Try making a change to some of the code in the main.dart
file and let Flutter recompile your app. You will notice that your changes do not immediately appear in the browser. This is because Flutter web does not yet support hot stateful reloading. Hopefully support for this awesome capability will come soon.
Now that you can run the weather app in the browser using Flutter, the next step is to build and copy it to the Node.js server to run alongside the API.
To build a Flutter web app bundle, run this command:
flutter build web
The build command will produce the build/web
folder containing all the static files that make up the weather app.
Copy the contents of weather_app_flutter/build/web
to weather-app-nodejs-server/public-flutter
. If your Node.js server in is still running, stop it and restart it to pick up the new files.
Access your Node.js server in the browser at http://localhost:3000
to see your app running on Node.js. This time, your app will display weather data retrieved from the weather API without the cross-origin resource sharing error.
It is incredible how simple it was to take an existing Flutter app and compile it into a web app ready to be deployed to a web server. The user interface rendered in the browser looks nearly identical to the user interface in Android.
Tread lightly if you are considering Flutter as your cross-platform app framework solely because of its web support. The Flutter team is very clear that web support is missing features, has known performance issues, and is not quite ready for production yet.
Thank for reading!
#node.js #flutter #javascript #wevdev #api
1656743400
This package provides unofficial localization support for Central Kurdish Branch Sorani (Kurdish: سۆرانی ,Soranî).
import 'package:flutter_kurdish_localization/flutter_kurdish_localization.dart';
Add these two delegates to localizationsDelegates array
KurdishMaterialLocalizations.delegate For text and dates localization KurdishWidgetLocalizations.delegate For text and UI directionality
return MaterialApp(
localizationsDelegates: [
..
KurdishMaterialLocalizations.delegate,
KurdishWidgetLocalizations.delegate,
...
],
supportedLocales: [ Locale('ku') ]
ocale: Locale('ku')
)
Run this command:
With Flutter:
$ flutter pub add flutter_kurdish_localization
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
flutter_kurdish_localization: ^0.0.9
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:flutter_kurdish_localization/flutter_kurdish_localization.dart';
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_kurdish_localization/flutter_kurdish_localization.dart';
import 'package:flutter_kurdish_localization_example/util/constants.dart';
import 'package:flutter_kurdish_localization_example/localization/demo_localization.dart';
import 'package:flutter_kurdish_localization_example/router/custom_router.dart';
import 'package:flutter_kurdish_localization_example/router/route_constants.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'localization/language_constants.dart';
bool? landingScreen;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences _prefs = await SharedPreferences.getInstance();
landingScreen = (_prefs.getBool('landing') ?? false);
if (landingScreen == true) {
debugPrint("Landing : $landingScreen");
} else {
debugPrint("Landing : $landingScreen");
}
runApp(const MyApp());
}
const List<Locale> supportedLocales = [
Locale('en'),
Locale('ku'),
Locale('ar'),
];
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
static void setLocale(BuildContext context, Locale newLocale) {
_MyAppState state = context.findAncestorStateOfType<_MyAppState>()!;
state.setLocale(newLocale);
}
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Locale? _locale;
setLocale(Locale locale) {
setState(() {
_locale = locale;
});
}
@override
void didChangeDependencies() {
getLocale().then((locale) {
setState(() {
_locale = locale;
});
});
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
systemNavigationBarColor: Colors.transparent, // navigation bar color
statusBarColor: primaryColor, // status bar color
statusBarIconBrightness: Brightness.light));
return MaterialApp(
debugShowCheckedModeBanner: false,
title: "Flutter Multi Localization Demo",
theme: ThemeData(primarySwatch: Colors.deepOrange),
locale: _locale,
supportedLocales: supportedLocales,
localizationsDelegates: const [
DemoLocalization.delegate,
KurdishMaterialLocalizations.delegate,
KurdishWidgetLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
localeResolutionCallback: (locale, supportedLocales) {
for (var supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale!.languageCode &&
supportedLocale.countryCode == locale.countryCode) {
return supportedLocale;
}
}
return supportedLocales.first;
},
onGenerateRoute: CustomRouter.generatedRoute,
initialRoute: landingScreen! ? homeRoute : landingRoute,
);
}
}
Author: Aminsamad
Source Code: https://github.com/aminsamad/flutter_kurdish_localization
License: GPL-3.0 license
1656740040
lifecycle_lite
通过简单几步,就可以让你使用whenShow()/whenHide()方法来监听页面的生命周期(退回到了该页面/打开其他页面挡着了该页面)了
这个库的实现很简单,你完全可以通过阅读代码后自己扩展实现。主要就是在MaterialApp
中添加一个对路由的监听,也就是MaterialApp#navigatorObservers
,之后通过对路由的监听来记录一个路由的栈。再在对应的State#initState
方法或StatelessWidget#createElement
中绑定两个生命周期方法的实现到最上层路由。 这样在每次监听到路由变化时,去调用顶层路由对应的绑定方法就OK了。 记得在路由被移出的时候对应的方法也要移出哦~
import 'package:lifecycle/lifecycle_mixin.dart';
1.首先在你的根布局MaterialApp
中绑定一个路由监听LifeNavigatorObserver()
.
MaterialApp(
navigatorObservers: [
LifeNavigatorObserver(),
],
);
2.在你需要添加监听的State中混入LifecycleMixin,并在initState中调用bindImplIntoRoute()方法。
2.StatefulWidget
的话,需要混入LifecycleStatefulMixin
,对应的StatelessWidget
,使用的是LifecycleStatelessMixin
3.实现whenShow()/whenHide()
方法,代码看起来是下面的样子。
///Statefule page
class WorksDetailState extends State with LifecycleStatefulMixin{
@override
whenShow() {
super.whenShow();
print("LifeNavigatorObserver---Show了");
}
@override
whenHide() {
super.whenHide();
print("LifeNavigatorObserver---Hide了");
}
}
///Stateless page
class StatelessPage extends StatelessWidget with LifecycleStatelessMixin{
@override
whenShow() {
super.whenShow();
print("LifeNavigatorObserver---Show了");
}
@override
whenHide() {
super.whenHide();
print("LifeNavigatorObserver---Hide了");
}
}
尽情享用吧 :P;
Run this command:
With Flutter:
$ flutter pub add lifecycle_lite
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
lifecycle_lite: ^0.0.3
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:lifecycle_lite/life_navigator_observer.dart';
import 'package:lifecycle_lite/lifecycle.dart';
import 'package:lifecycle_lite/lifecycle_export.dart';
import 'package:lifecycle_lite/lifecycle_mixin.dart';
import 'package:lifecycle_lite/utils.dart';
1656738420
A light-weight library for working with commits that follow the Conventional Commits specification.
git --no-pager log --no-decorate
command output.Commit
items has releasable commits following the convention.A simple usage example:
import 'package:conventional/conventional.dart';
main() {
final List<Commit> commits = Commit.parseCommits(testLog);
if (hasReleasableCommits(commits)) {
writeChangelog(
commits: commits,
changelogFilePath: 'CHANGELOG.md',
version: '1.2.0',
now: DateTime.now(),
);
}
}
Run this command:
With Dart:
$ dart pub add conventional
With Flutter:
$ flutter pub add conventional
This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get
):
dependencies:
conventional: ^0.3.0
Alternatively, your editor might support dart pub get
or flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:conventional/conventional.dart';
example/conventional_example.dart
import 'package:conventional/conventional.dart';
// ignore_for_file: avoid_print
const testLog = '''
commit fc9d8117b1074c3c965c5c1ccf845d784c026ac7
Author: Jane Doe <jane.doe@example.com>
Date: Mon Feb 8 15:26:49 2021 +0800
ci: fix release workflow
commit cf6080079cd96cb4ccc2edca2ba9cacbcfd64704
Author: Jane Doe <jane.doe@example.com>
Date: Sun Feb 7 12:58:06 2021 +0800
ci: try fixing problem with release
commit 925fcd38fe8bd2653ea70d67155b8e31082cf4b2
Author: Jane Doe <jane.doe@example.com>
Date: Fri Feb 5 16:24:38 2021 +0800
chore: fix analysis errors
- disabled checking for non null-safe libraries (temporary)
- annotation for DatabaseLogWrapper
commit 43cf9b78f77a0180ad408cb87e8a774a530619ce
Author: Jane Doe <jane.doe@example.com>
Date: Fri Feb 5 11:56:26 2021 +0800
feat: null-safety and piechart cache
BREAKING CHANGE: uses null-safety
commit e86efaced15f875ae9e11fd0d79b72d85578f79a
Author: Jane Doe <jane.doe@example.com>
Date: Wed Jan 27 18:20:41 2021 +0800
chore: wip to null-safety
commit 18bf98f5cddfecc69b26285b6edca063f1a8b1ec
Merge: b457270 dc60e12
Author: Jane Doe <jane.doe@example.com>
Date: Sat Dec 19 13:28:47 2020 +0800
ci: Merge pull request #3 from asartalo/semantic-release
ci: fixing semantic-release config
''';
void main() {
// Parse commits
final List<Commit> commits = Commit.parseCommits(testLog);
final firstCommit = commits.first;
print(firstCommit.author.name); // "Jane Doe"
print(firstCommit.author.email); // "jane.doe@example.com"
print(firstCommit.breaking); // false
print(firstCommit.type); // "ci"
print(firstCommit.description); // "fix release workflow"
// Check if we have releasable commits
final shouldRelease = hasReleasableCommits(commits);
print(shouldRelease); // true
if (shouldRelease) {
// Write to a changelog file
writeChangelog(
commits: commits,
changelogFilePath: 'CHANGELOG.md',
version: '1.2.0',
now: DateTime.now(),
);
}
}
Please file feature requests and bugs at the issue tracker. PR's are welcome and appreciated!
Author: Asartalo
Source Code: https://github.com/asartalo/conventional
License: MIT license