Committed by
GitHub
Merge pull request #2048 from parmarravi/master
Added Circular reveal Transition
Showing
16 changed files
with
360 additions
and
90 deletions
No preview for this file type
@@ -328,7 +328,7 @@ Text(controller.textFromApi); | @@ -328,7 +328,7 @@ Text(controller.textFromApi); | ||
328 | 328 | ||
329 | ### 종속성 관리에 대한 자세한 내용 | 329 | ### 종속성 관리에 대한 자세한 내용 |
330 | 330 | ||
331 | -**종속성 관리에 대한 더 제사한 사항은 [여기](./documentation/kr_KO/dependency_management.md)에 있습니다.** | 331 | +**종속성 관리에 대한 더 자세한 사항은 [여기](./documentation/kr_KO/dependency_management.md)에 있습니다.** |
332 | 332 | ||
333 | # 기능들 | 333 | # 기능들 |
334 | 334 | ||
@@ -1092,6 +1092,73 @@ class SettingsService extends GetxService { | @@ -1092,6 +1092,73 @@ class SettingsService extends GetxService { | ||
1092 | 따라서 앱 실행중 절대로 유지되어야 하는 클래스 인스턴스가 필요하면 | 1092 | 따라서 앱 실행중 절대로 유지되어야 하는 클래스 인스턴스가 필요하면 |
1093 | `GetxService`를 사용하세요. | 1093 | `GetxService`를 사용하세요. |
1094 | 1094 | ||
1095 | +### 테스트 | ||
1096 | + | ||
1097 | +당신은 당신의 컨트롤러들을 생성주기를 포함하여 다른 어떤 클래스처럼 테스트할 수 있습니다 : | ||
1098 | + | ||
1099 | +```dart | ||
1100 | +class Controller extends GetxController { | ||
1101 | + @override | ||
1102 | + void onInit() { | ||
1103 | + super.onInit(); | ||
1104 | + //name2로 값 변경 | ||
1105 | + name.value = 'name2'; | ||
1106 | + } | ||
1107 | + | ||
1108 | + @override | ||
1109 | + void onClose() { | ||
1110 | + name.value = ''; | ||
1111 | + super.onClose(); | ||
1112 | + } | ||
1113 | + | ||
1114 | + final name = 'name1'.obs; | ||
1115 | + | ||
1116 | + void changeName() => name.value = 'name3'; | ||
1117 | +} | ||
1118 | + | ||
1119 | +void main() { | ||
1120 | + test(''' | ||
1121 | +Test the state of the reactive variable "name" across all of its lifecycles''', | ||
1122 | + () { | ||
1123 | + /// 당신은 생성주기를 제외하고 컨트롤러를 테스트할 수 있습니다, | ||
1124 | + /// 그러나 당신이 사용하지 않는다면 추천되지 않습니다 | ||
1125 | + /// GetX 종속성 주입 | ||
1126 | + final controller = Controller(); | ||
1127 | + expect(controller.name.value, 'name1'); | ||
1128 | + | ||
1129 | + /// 당신이 그것을 사용한다면, 당신은 모든 것을 테스트할 수 있습니다, | ||
1130 | + /// 각각의 생성주기 이후 어플리케이션의 상태를 포함하여. | ||
1131 | + Get.put(controller); // onInit was called | ||
1132 | + expect(controller.name.value, 'name2'); | ||
1133 | + | ||
1134 | + /// 당신의 함수를 테스트하세요 | ||
1135 | + controller.changeName(); | ||
1136 | + expect(controller.name.value, 'name3'); | ||
1137 | + | ||
1138 | + /// onClose 호출됨 | ||
1139 | + Get.delete<Controller>(); | ||
1140 | + | ||
1141 | + expect(controller.name.value, ''); | ||
1142 | + }); | ||
1143 | +} | ||
1144 | +``` | ||
1145 | + | ||
1146 | +#### 팁들 | ||
1147 | + | ||
1148 | +##### Mockito 또는 mocktail | ||
1149 | +당신이 당신의 GetxController/GetxService를 모킹하려고 한다면, 당신은 GetxController를 extend 하고, Mock과 mixin 하라, 그렇게 되면 | ||
1150 | + | ||
1151 | +```dart | ||
1152 | +class NotificationServiceMock extends GetxService with Mock implements NotificationService {} | ||
1153 | +``` | ||
1154 | + | ||
1155 | +##### Get.reset() 사용하기 | ||
1156 | +당신이 위젯 또는 테스트 그룹을 테스트하고 있다면, 당신의 테스트의 마지막 또는 해제 때 당신의 이전 테스트에서 모든 설정을 리셋하기 위해 Get.rest을 사용하십시오 | ||
1157 | + | ||
1158 | +##### Get.testMode | ||
1159 | +당신이 당신의 컨트롤러에서 당신의 네비게이션을 사용하고 있다면, 당신의 메인의 시작에 `Get.testMode = true` 를 사용하십시오. | ||
1160 | + | ||
1161 | + | ||
1095 | # 2.0의 주요 변경점 | 1162 | # 2.0의 주요 변경점 |
1096 | 1163 | ||
1097 | 1- Rx 타입들: | 1164 | 1- Rx 타입들: |
@@ -115,6 +115,7 @@ class GetConnect extends GetConnectInterface { | @@ -115,6 +115,7 @@ class GetConnect extends GetConnectInterface { | ||
115 | Decoder? defaultDecoder; | 115 | Decoder? defaultDecoder; |
116 | Duration timeout; | 116 | Duration timeout; |
117 | List<TrustedCertificate>? trustedCertificates; | 117 | List<TrustedCertificate>? trustedCertificates; |
118 | + String Function(Uri url)? findProxy; | ||
118 | GetHttpClient? _httpClient; | 119 | GetHttpClient? _httpClient; |
119 | List<GetSocket>? _sockets; | 120 | List<GetSocket>? _sockets; |
120 | bool withCredentials; | 121 | bool withCredentials; |
@@ -134,6 +135,7 @@ class GetConnect extends GetConnectInterface { | @@ -134,6 +135,7 @@ class GetConnect extends GetConnectInterface { | ||
134 | baseUrl: baseUrl, | 135 | baseUrl: baseUrl, |
135 | trustedCertificates: trustedCertificates, | 136 | trustedCertificates: trustedCertificates, |
136 | withCredentials: withCredentials, | 137 | withCredentials: withCredentials, |
138 | + findProxy: findProxy | ||
137 | ); | 139 | ); |
138 | 140 | ||
139 | @override | 141 | @override |
@@ -39,6 +39,8 @@ class GetHttpClient { | @@ -39,6 +39,8 @@ class GetHttpClient { | ||
39 | 39 | ||
40 | final GetModifier _modifier; | 40 | final GetModifier _modifier; |
41 | 41 | ||
42 | + String Function(Uri url)? findProxy; | ||
43 | + | ||
42 | GetHttpClient({ | 44 | GetHttpClient({ |
43 | this.userAgent = 'getx-client', | 45 | this.userAgent = 'getx-client', |
44 | this.timeout = const Duration(seconds: 8), | 46 | this.timeout = const Duration(seconds: 8), |
@@ -50,10 +52,12 @@ class GetHttpClient { | @@ -50,10 +52,12 @@ class GetHttpClient { | ||
50 | this.baseUrl, | 52 | this.baseUrl, |
51 | List<TrustedCertificate>? trustedCertificates, | 53 | List<TrustedCertificate>? trustedCertificates, |
52 | bool withCredentials = false, | 54 | bool withCredentials = false, |
55 | + String Function(Uri url)? findProxy, | ||
53 | }) : _httpClient = HttpRequestImpl( | 56 | }) : _httpClient = HttpRequestImpl( |
54 | allowAutoSignedCert: allowAutoSignedCert, | 57 | allowAutoSignedCert: allowAutoSignedCert, |
55 | trustedCertificates: trustedCertificates, | 58 | trustedCertificates: trustedCertificates, |
56 | withCredentials: withCredentials, | 59 | withCredentials: withCredentials, |
60 | + findProxy: findProxy, | ||
57 | ), | 61 | ), |
58 | _modifier = GetModifier(); | 62 | _modifier = GetModifier(); |
59 | 63 | ||
@@ -195,7 +199,6 @@ class GetHttpClient { | @@ -195,7 +199,6 @@ class GetHttpClient { | ||
195 | int requestNumber = 1, | 199 | int requestNumber = 1, |
196 | Map<String, String>? headers, | 200 | Map<String, String>? headers, |
197 | }) async { | 201 | }) async { |
198 | - try { | ||
199 | var request = await handler(); | 202 | var request = await handler(); |
200 | 203 | ||
201 | headers?.forEach((key, value) { | 204 | headers?.forEach((key, value) { |
@@ -206,6 +209,7 @@ class GetHttpClient { | @@ -206,6 +209,7 @@ class GetHttpClient { | ||
206 | final newRequest = await _modifier.modifyRequest<T>(request); | 209 | final newRequest = await _modifier.modifyRequest<T>(request); |
207 | 210 | ||
208 | _httpClient.timeout = timeout; | 211 | _httpClient.timeout = timeout; |
212 | + try { | ||
209 | var response = await _httpClient.send<T>(newRequest); | 213 | var response = await _httpClient.send<T>(newRequest); |
210 | 214 | ||
211 | final newResponse = | 215 | final newResponse = |
@@ -242,7 +246,7 @@ class GetHttpClient { | @@ -242,7 +246,7 @@ class GetHttpClient { | ||
242 | throw GetHttpException(err.toString()); | 246 | throw GetHttpException(err.toString()); |
243 | } else { | 247 | } else { |
244 | return Response<T>( | 248 | return Response<T>( |
245 | - request: null, | 249 | + request: newRequest, |
246 | headers: null, | 250 | headers: null, |
247 | statusCode: null, | 251 | statusCode: null, |
248 | body: null, | 252 | body: null, |
@@ -268,6 +272,8 @@ class GetHttpClient { | @@ -268,6 +272,8 @@ class GetHttpClient { | ||
268 | headers: headers, | 272 | headers: headers, |
269 | decoder: decoder ?? (defaultDecoder as Decoder<T>?), | 273 | decoder: decoder ?? (defaultDecoder as Decoder<T>?), |
270 | contentLength: 0, | 274 | contentLength: 0, |
275 | + followRedirects: followRedirects, | ||
276 | + maxRedirects: maxRedirects, | ||
271 | )); | 277 | )); |
272 | } | 278 | } |
273 | 279 |
@@ -17,6 +17,7 @@ class HttpRequestImpl extends HttpRequestBase { | @@ -17,6 +17,7 @@ class HttpRequestImpl extends HttpRequestBase { | ||
17 | bool allowAutoSignedCert = true, | 17 | bool allowAutoSignedCert = true, |
18 | List<TrustedCertificate>? trustedCertificates, | 18 | List<TrustedCertificate>? trustedCertificates, |
19 | bool withCredentials = false, | 19 | bool withCredentials = false, |
20 | + String Function(Uri url)? findProxy, | ||
20 | }) { | 21 | }) { |
21 | _httpClient = io.HttpClient(); | 22 | _httpClient = io.HttpClient(); |
22 | if (trustedCertificates != null) { | 23 | if (trustedCertificates != null) { |
@@ -29,6 +30,7 @@ class HttpRequestImpl extends HttpRequestBase { | @@ -29,6 +30,7 @@ class HttpRequestImpl extends HttpRequestBase { | ||
29 | 30 | ||
30 | _httpClient = io.HttpClient(context: _securityContext); | 31 | _httpClient = io.HttpClient(context: _securityContext); |
31 | _httpClient!.badCertificateCallback = (_, __, ___) => allowAutoSignedCert; | 32 | _httpClient!.badCertificateCallback = (_, __, ___) => allowAutoSignedCert; |
33 | + _httpClient!.findProxy = findProxy; | ||
32 | } | 34 | } |
33 | 35 | ||
34 | @override | 36 | @override |
@@ -8,6 +8,7 @@ class HttpRequestImpl extends HttpRequestBase { | @@ -8,6 +8,7 @@ class HttpRequestImpl extends HttpRequestBase { | ||
8 | bool allowAutoSignedCert = true, | 8 | bool allowAutoSignedCert = true, |
9 | List<TrustedCertificate>? trustedCertificates, | 9 | List<TrustedCertificate>? trustedCertificates, |
10 | bool withCredentials = false, | 10 | bool withCredentials = false, |
11 | + String Function(Uri url)? findProxy, | ||
11 | }); | 12 | }); |
12 | @override | 13 | @override |
13 | void close() {} | 14 | void close() {} |
@@ -239,7 +239,7 @@ class GetInstance { | @@ -239,7 +239,7 @@ class GetInstance { | ||
239 | final newKey = key ?? _getKey(S, tag); | 239 | final newKey = key ?? _getKey(S, tag); |
240 | if (_singl.containsKey(newKey)) { | 240 | if (_singl.containsKey(newKey)) { |
241 | final dep = _singl[newKey]; | 241 | final dep = _singl[newKey]; |
242 | - if (dep != null) { | 242 | + if (dep != null && !dep.permanent) { |
243 | dep.isDirty = true; | 243 | dep.isDirty = true; |
244 | } | 244 | } |
245 | } | 245 | } |
1 | import 'package:flutter/cupertino.dart'; | 1 | import 'package:flutter/cupertino.dart'; |
2 | import 'package:flutter/foundation.dart'; | 2 | import 'package:flutter/foundation.dart'; |
3 | import 'package:flutter/material.dart'; | 3 | import 'package:flutter/material.dart'; |
4 | + | ||
4 | import '../../../get_core/get_core.dart'; | 5 | import '../../../get_core/get_core.dart'; |
5 | import '../../../get_instance/get_instance.dart'; | 6 | import '../../../get_instance/get_instance.dart'; |
6 | import '../../../get_state_manager/get_state_manager.dart'; | 7 | import '../../../get_state_manager/get_state_manager.dart'; |
@@ -9,6 +10,59 @@ import '../../get_navigation.dart'; | @@ -9,6 +10,59 @@ import '../../get_navigation.dart'; | ||
9 | import 'root_controller.dart'; | 10 | import 'root_controller.dart'; |
10 | 11 | ||
11 | class GetCupertinoApp extends StatelessWidget { | 12 | class GetCupertinoApp extends StatelessWidget { |
13 | + final GlobalKey<NavigatorState>? navigatorKey; | ||
14 | + | ||
15 | + final Widget? home; | ||
16 | + final Map<String, WidgetBuilder>? routes; | ||
17 | + final String? initialRoute; | ||
18 | + final RouteFactory? onGenerateRoute; | ||
19 | + final InitialRouteListFactory? onGenerateInitialRoutes; | ||
20 | + final RouteFactory? onUnknownRoute; | ||
21 | + final List<NavigatorObserver>? navigatorObservers; | ||
22 | + final TransitionBuilder? builder; | ||
23 | + final String title; | ||
24 | + final GenerateAppTitle? onGenerateTitle; | ||
25 | + final CustomTransition? customTransition; | ||
26 | + final Color? color; | ||
27 | + final Map<String, Map<String, String>>? translationsKeys; | ||
28 | + final Translations? translations; | ||
29 | + final TextDirection? textDirection; | ||
30 | + final Locale? locale; | ||
31 | + final Locale? fallbackLocale; | ||
32 | + final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates; | ||
33 | + final LocaleListResolutionCallback? localeListResolutionCallback; | ||
34 | + final LocaleResolutionCallback? localeResolutionCallback; | ||
35 | + final Iterable<Locale> supportedLocales; | ||
36 | + final bool showPerformanceOverlay; | ||
37 | + final bool checkerboardRasterCacheImages; | ||
38 | + final bool checkerboardOffscreenLayers; | ||
39 | + final bool showSemanticsDebugger; | ||
40 | + final bool debugShowCheckedModeBanner; | ||
41 | + final Map<LogicalKeySet, Intent>? shortcuts; | ||
42 | + final ThemeData? highContrastTheme; | ||
43 | + final ThemeData? highContrastDarkTheme; | ||
44 | + final Map<Type, Action<Intent>>? actions; | ||
45 | + final Function(Routing?)? routingCallback; | ||
46 | + final Transition? defaultTransition; | ||
47 | + final bool? opaqueRoute; | ||
48 | + final VoidCallback? onInit; | ||
49 | + final VoidCallback? onReady; | ||
50 | + final VoidCallback? onDispose; | ||
51 | + final bool? enableLog; | ||
52 | + final LogWriterCallback? logWriterCallback; | ||
53 | + final bool? popGesture; | ||
54 | + final SmartManagement smartManagement; | ||
55 | + final Bindings? initialBinding; | ||
56 | + final Duration? transitionDuration; | ||
57 | + final bool? defaultGlobalState; | ||
58 | + final List<GetPage>? getPages; | ||
59 | + final GetPage? unknownRoute; | ||
60 | + final RouteInformationProvider? routeInformationProvider; | ||
61 | + final RouteInformationParser<Object>? routeInformationParser; | ||
62 | + final RouterDelegate<Object>? routerDelegate; | ||
63 | + final BackButtonDispatcher? backButtonDispatcher; | ||
64 | + final CupertinoThemeData? theme; | ||
65 | + final bool useInheritedMediaQuery; | ||
12 | const GetCupertinoApp({ | 66 | const GetCupertinoApp({ |
13 | Key? key, | 67 | Key? key, |
14 | this.theme, | 68 | this.theme, |
@@ -46,6 +100,7 @@ class GetCupertinoApp extends StatelessWidget { | @@ -46,6 +100,7 @@ class GetCupertinoApp extends StatelessWidget { | ||
46 | this.shortcuts, | 100 | this.shortcuts, |
47 | this.smartManagement = SmartManagement.full, | 101 | this.smartManagement = SmartManagement.full, |
48 | this.initialBinding, | 102 | this.initialBinding, |
103 | + this.useInheritedMediaQuery = false, | ||
49 | this.unknownRoute, | 104 | this.unknownRoute, |
50 | this.routingCallback, | 105 | this.routingCallback, |
51 | this.defaultTransition, | 106 | this.defaultTransition, |
@@ -66,58 +121,6 @@ class GetCupertinoApp extends StatelessWidget { | @@ -66,58 +121,6 @@ class GetCupertinoApp extends StatelessWidget { | ||
66 | backButtonDispatcher = null, | 121 | backButtonDispatcher = null, |
67 | super(key: key); | 122 | super(key: key); |
68 | 123 | ||
69 | - final GlobalKey<NavigatorState>? navigatorKey; | ||
70 | - final Widget? home; | ||
71 | - final Map<String, WidgetBuilder>? routes; | ||
72 | - final String? initialRoute; | ||
73 | - final RouteFactory? onGenerateRoute; | ||
74 | - final InitialRouteListFactory? onGenerateInitialRoutes; | ||
75 | - final RouteFactory? onUnknownRoute; | ||
76 | - final List<NavigatorObserver>? navigatorObservers; | ||
77 | - final TransitionBuilder? builder; | ||
78 | - final String title; | ||
79 | - final GenerateAppTitle? onGenerateTitle; | ||
80 | - final CustomTransition? customTransition; | ||
81 | - final Color? color; | ||
82 | - final Map<String, Map<String, String>>? translationsKeys; | ||
83 | - final Translations? translations; | ||
84 | - final TextDirection? textDirection; | ||
85 | - final Locale? locale; | ||
86 | - final Locale? fallbackLocale; | ||
87 | - final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates; | ||
88 | - final LocaleListResolutionCallback? localeListResolutionCallback; | ||
89 | - final LocaleResolutionCallback? localeResolutionCallback; | ||
90 | - final Iterable<Locale> supportedLocales; | ||
91 | - final bool showPerformanceOverlay; | ||
92 | - final bool checkerboardRasterCacheImages; | ||
93 | - final bool checkerboardOffscreenLayers; | ||
94 | - final bool showSemanticsDebugger; | ||
95 | - final bool debugShowCheckedModeBanner; | ||
96 | - final Map<LogicalKeySet, Intent>? shortcuts; | ||
97 | - final ThemeData? highContrastTheme; | ||
98 | - final ThemeData? highContrastDarkTheme; | ||
99 | - final Map<Type, Action<Intent>>? actions; | ||
100 | - final Function(Routing?)? routingCallback; | ||
101 | - final Transition? defaultTransition; | ||
102 | - final bool? opaqueRoute; | ||
103 | - final VoidCallback? onInit; | ||
104 | - final VoidCallback? onReady; | ||
105 | - final VoidCallback? onDispose; | ||
106 | - final bool? enableLog; | ||
107 | - final LogWriterCallback? logWriterCallback; | ||
108 | - final bool? popGesture; | ||
109 | - final SmartManagement smartManagement; | ||
110 | - final Bindings? initialBinding; | ||
111 | - final Duration? transitionDuration; | ||
112 | - final bool? defaultGlobalState; | ||
113 | - final List<GetPage>? getPages; | ||
114 | - final GetPage? unknownRoute; | ||
115 | - final RouteInformationProvider? routeInformationProvider; | ||
116 | - final RouteInformationParser<Object>? routeInformationParser; | ||
117 | - final RouterDelegate<Object>? routerDelegate; | ||
118 | - final BackButtonDispatcher? backButtonDispatcher; | ||
119 | - final CupertinoThemeData? theme; | ||
120 | - | ||
121 | GetCupertinoApp.router({ | 124 | GetCupertinoApp.router({ |
122 | Key? key, | 125 | Key? key, |
123 | this.theme, | 126 | this.theme, |
@@ -128,6 +131,7 @@ class GetCupertinoApp extends StatelessWidget { | @@ -128,6 +131,7 @@ class GetCupertinoApp extends StatelessWidget { | ||
128 | this.builder, | 131 | this.builder, |
129 | this.title = '', | 132 | this.title = '', |
130 | this.onGenerateTitle, | 133 | this.onGenerateTitle, |
134 | + this.useInheritedMediaQuery = false, | ||
131 | this.color, | 135 | this.color, |
132 | this.highContrastTheme, | 136 | this.highContrastTheme, |
133 | this.highContrastDarkTheme, | 137 | this.highContrastDarkTheme, |
@@ -183,31 +187,6 @@ class GetCupertinoApp extends StatelessWidget { | @@ -183,31 +187,6 @@ class GetCupertinoApp extends StatelessWidget { | ||
183 | Get.routeInformationParser = routeInformationParser; | 187 | Get.routeInformationParser = routeInformationParser; |
184 | } | 188 | } |
185 | 189 | ||
186 | - Route<dynamic> generator(RouteSettings settings) { | ||
187 | - return PageRedirect(settings: settings, unknownRoute: unknownRoute).page(); | ||
188 | - } | ||
189 | - | ||
190 | - List<Route<dynamic>> initialRoutesGenerate(String name) { | ||
191 | - return [ | ||
192 | - PageRedirect( | ||
193 | - settings: RouteSettings(name: name), | ||
194 | - unknownRoute: unknownRoute, | ||
195 | - ).page() | ||
196 | - ]; | ||
197 | - } | ||
198 | - | ||
199 | - Widget defaultBuilder(BuildContext context, Widget? child) { | ||
200 | - return Directionality( | ||
201 | - textDirection: textDirection ?? | ||
202 | - (rtlLanguages.contains(Get.locale?.languageCode) | ||
203 | - ? TextDirection.rtl | ||
204 | - : TextDirection.ltr), | ||
205 | - child: builder == null | ||
206 | - ? (child ?? Material()) | ||
207 | - : builder!(context, child ?? Material()), | ||
208 | - ); | ||
209 | - } | ||
210 | - | ||
211 | @override | 190 | @override |
212 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( | 191 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( |
213 | init: Get.rootController, | 192 | init: Get.rootController, |
@@ -271,6 +250,7 @@ class GetCupertinoApp extends StatelessWidget { | @@ -271,6 +250,7 @@ class GetCupertinoApp extends StatelessWidget { | ||
271 | showSemanticsDebugger: showSemanticsDebugger, | 250 | showSemanticsDebugger: showSemanticsDebugger, |
272 | debugShowCheckedModeBanner: debugShowCheckedModeBanner, | 251 | debugShowCheckedModeBanner: debugShowCheckedModeBanner, |
273 | shortcuts: shortcuts, | 252 | shortcuts: shortcuts, |
253 | + useInheritedMediaQuery: useInheritedMediaQuery, | ||
274 | ) | 254 | ) |
275 | : CupertinoApp( | 255 | : CupertinoApp( |
276 | key: _.unikey, | 256 | key: _.unikey, |
@@ -310,7 +290,33 @@ class GetCupertinoApp extends StatelessWidget { | @@ -310,7 +290,33 @@ class GetCupertinoApp extends StatelessWidget { | ||
310 | showSemanticsDebugger: showSemanticsDebugger, | 290 | showSemanticsDebugger: showSemanticsDebugger, |
311 | debugShowCheckedModeBanner: debugShowCheckedModeBanner, | 291 | debugShowCheckedModeBanner: debugShowCheckedModeBanner, |
312 | shortcuts: shortcuts, | 292 | shortcuts: shortcuts, |
293 | + useInheritedMediaQuery: useInheritedMediaQuery, | ||
313 | // actions: actions, | 294 | // actions: actions, |
314 | ), | 295 | ), |
315 | ); | 296 | ); |
297 | + | ||
298 | + Widget defaultBuilder(BuildContext context, Widget? child) { | ||
299 | + return Directionality( | ||
300 | + textDirection: textDirection ?? | ||
301 | + (rtlLanguages.contains(Get.locale?.languageCode) | ||
302 | + ? TextDirection.rtl | ||
303 | + : TextDirection.ltr), | ||
304 | + child: builder == null | ||
305 | + ? (child ?? Material()) | ||
306 | + : builder!(context, child ?? Material()), | ||
307 | + ); | ||
308 | + } | ||
309 | + | ||
310 | + Route<dynamic> generator(RouteSettings settings) { | ||
311 | + return PageRedirect(settings: settings, unknownRoute: unknownRoute).page(); | ||
312 | + } | ||
313 | + | ||
314 | + List<Route<dynamic>> initialRoutesGenerate(String name) { | ||
315 | + return [ | ||
316 | + PageRedirect( | ||
317 | + settings: RouteSettings(name: name), | ||
318 | + unknownRoute: unknownRoute, | ||
319 | + ).page() | ||
320 | + ]; | ||
321 | + } | ||
316 | } | 322 | } |
@@ -67,6 +67,7 @@ class GetMaterialApp extends StatelessWidget { | @@ -67,6 +67,7 @@ class GetMaterialApp extends StatelessWidget { | ||
67 | final RouteInformationParser<Object>? routeInformationParser; | 67 | final RouteInformationParser<Object>? routeInformationParser; |
68 | final RouterDelegate<Object>? routerDelegate; | 68 | final RouterDelegate<Object>? routerDelegate; |
69 | final BackButtonDispatcher? backButtonDispatcher; | 69 | final BackButtonDispatcher? backButtonDispatcher; |
70 | + final bool useInheritedMediaQuery; | ||
70 | const GetMaterialApp({ | 71 | const GetMaterialApp({ |
71 | Key? key, | 72 | Key? key, |
72 | this.navigatorKey, | 73 | this.navigatorKey, |
@@ -78,6 +79,7 @@ class GetMaterialApp extends StatelessWidget { | @@ -78,6 +79,7 @@ class GetMaterialApp extends StatelessWidget { | ||
78 | this.onGenerateRoute, | 79 | this.onGenerateRoute, |
79 | this.onGenerateInitialRoutes, | 80 | this.onGenerateInitialRoutes, |
80 | this.onUnknownRoute, | 81 | this.onUnknownRoute, |
82 | + this.useInheritedMediaQuery = false, | ||
81 | List<NavigatorObserver> this.navigatorObservers = | 83 | List<NavigatorObserver> this.navigatorObservers = |
82 | const <NavigatorObserver>[], | 84 | const <NavigatorObserver>[], |
83 | this.builder, | 85 | this.builder, |
@@ -142,6 +144,7 @@ class GetMaterialApp extends StatelessWidget { | @@ -142,6 +144,7 @@ class GetMaterialApp extends StatelessWidget { | ||
142 | this.color, | 144 | this.color, |
143 | this.theme, | 145 | this.theme, |
144 | this.darkTheme, | 146 | this.darkTheme, |
147 | + this.useInheritedMediaQuery = false, | ||
145 | this.highContrastTheme, | 148 | this.highContrastTheme, |
146 | this.highContrastDarkTheme, | 149 | this.highContrastDarkTheme, |
147 | this.themeMode = ThemeMode.system, | 150 | this.themeMode = ThemeMode.system, |
@@ -271,6 +274,7 @@ class GetMaterialApp extends StatelessWidget { | @@ -271,6 +274,7 @@ class GetMaterialApp extends StatelessWidget { | ||
271 | debugShowCheckedModeBanner: debugShowCheckedModeBanner, | 274 | debugShowCheckedModeBanner: debugShowCheckedModeBanner, |
272 | shortcuts: shortcuts, | 275 | shortcuts: shortcuts, |
273 | scrollBehavior: scrollBehavior, | 276 | scrollBehavior: scrollBehavior, |
277 | + useInheritedMediaQuery: useInheritedMediaQuery, | ||
274 | ) | 278 | ) |
275 | : MaterialApp( | 279 | : MaterialApp( |
276 | key: _.unikey, | 280 | key: _.unikey, |
@@ -317,6 +321,7 @@ class GetMaterialApp extends StatelessWidget { | @@ -317,6 +321,7 @@ class GetMaterialApp extends StatelessWidget { | ||
317 | debugShowCheckedModeBanner: debugShowCheckedModeBanner, | 321 | debugShowCheckedModeBanner: debugShowCheckedModeBanner, |
318 | shortcuts: shortcuts, | 322 | shortcuts: shortcuts, |
319 | scrollBehavior: scrollBehavior, | 323 | scrollBehavior: scrollBehavior, |
324 | + useInheritedMediaQuery: useInheritedMediaQuery, | ||
320 | // actions: actions, | 325 | // actions: actions, |
321 | ), | 326 | ), |
322 | ); | 327 | ); |
1 | +import 'dart:math' show sqrt, max; | ||
2 | +import 'dart:ui' show lerpDouble; | ||
3 | + | ||
4 | +import 'package:flutter/material.dart'; | ||
5 | + | ||
6 | +class CircularRevealClipper extends CustomClipper<Path> { | ||
7 | + final double fraction; | ||
8 | + final Alignment? centerAlignment; | ||
9 | + final Offset? centerOffset; | ||
10 | + final double? minRadius; | ||
11 | + final double? maxRadius; | ||
12 | + | ||
13 | + CircularRevealClipper({ | ||
14 | + required this.fraction, | ||
15 | + this.centerAlignment, | ||
16 | + this.centerOffset, | ||
17 | + this.minRadius, | ||
18 | + this.maxRadius, | ||
19 | + }); | ||
20 | + | ||
21 | + @override | ||
22 | + Path getClip(Size size) { | ||
23 | + final Offset center = this.centerAlignment?.alongSize(size) ?? | ||
24 | + this.centerOffset ?? | ||
25 | + Offset(size.width / 2, size.height / 2); | ||
26 | + final minRadius = this.minRadius ?? 0; | ||
27 | + final maxRadius = this.maxRadius ?? calcMaxRadius(size, center); | ||
28 | + | ||
29 | + return Path() | ||
30 | + ..addOval( | ||
31 | + Rect.fromCircle( | ||
32 | + center: center, | ||
33 | + radius: lerpDouble(minRadius, maxRadius, fraction)!, | ||
34 | + ), | ||
35 | + ); | ||
36 | + } | ||
37 | + | ||
38 | + @override | ||
39 | + bool shouldReclip(CustomClipper<Path> oldClipper) => true; | ||
40 | + | ||
41 | + static double calcMaxRadius(Size size, Offset center) { | ||
42 | + final w = max(center.dx, size.width - center.dx); | ||
43 | + final h = max(center.dy, size.height - center.dy); | ||
44 | + return sqrt(w * w + h * h); | ||
45 | + } | ||
46 | +} | ||
47 | + |
@@ -184,3 +184,26 @@ class SizeTransitions { | @@ -184,3 +184,26 @@ class SizeTransitions { | ||
184 | ); | 184 | ); |
185 | } | 185 | } |
186 | } | 186 | } |
187 | + | ||
188 | + | ||
189 | +class CircularRevealTransition { | ||
190 | + Widget buildTransitions( | ||
191 | + BuildContext context, | ||
192 | + Curve? curve, | ||
193 | + Alignment? alignment, | ||
194 | + Animation<double> animation, | ||
195 | + Animation<double> secondaryAnimation, | ||
196 | + Widget child) { | ||
197 | + return ClipPath( | ||
198 | + clipper: CircularRevealClipper( | ||
199 | + fraction: animation.value, | ||
200 | + centerAlignment: Alignment.center, | ||
201 | + centerOffset: Offset.zero, | ||
202 | + minRadius: 0, | ||
203 | + maxRadius: 800, | ||
204 | + ), | ||
205 | + child: child, | ||
206 | + ); | ||
207 | + } | ||
208 | +} | ||
209 | + |
@@ -620,6 +620,22 @@ Cannot read the previousTitle for a route that has not yet been installed''', | @@ -620,6 +620,22 @@ Cannot read the previousTitle for a route that has not yet been installed''', | ||
620 | child: child) | 620 | child: child) |
621 | : child); | 621 | : child); |
622 | 622 | ||
623 | + case Transition.ciruclarReveal: | ||
624 | + return CircularRevealTransition().buildTransitions( | ||
625 | + context, | ||
626 | + route.curve, | ||
627 | + route.alignment, | ||
628 | + animation, | ||
629 | + secondaryAnimation, | ||
630 | + route.popGesture ?? Get.defaultPopGesture | ||
631 | + ? CupertinoBackGestureDetector<T>( | ||
632 | + gestureWidth: route.gestureWidth?.call(context) ?? | ||
633 | + _kBackGestureWidth, | ||
634 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
635 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
636 | + child: child) | ||
637 | + : child); | ||
638 | + | ||
623 | default: | 639 | default: |
624 | if (Get.customTransition != null) { | 640 | if (Get.customTransition != null) { |
625 | return Get.customTransition!.buildTransition(context, route.curve, | 641 | return Get.customTransition!.buildTransition(context, route.curve, |
@@ -67,6 +67,7 @@ mixin RxObjectMixin<T> on NotifyManager<T> { | @@ -67,6 +67,7 @@ mixin RxObjectMixin<T> on NotifyManager<T> { | ||
67 | } | 67 | } |
68 | 68 | ||
69 | bool firstRebuild = true; | 69 | bool firstRebuild = true; |
70 | + bool sentToStream = false; | ||
70 | 71 | ||
71 | /// Same as `toString()` but using a getter. | 72 | /// Same as `toString()` but using a getter. |
72 | String get string => value.toString(); | 73 | String get string => value.toString(); |
@@ -96,10 +97,11 @@ mixin RxObjectMixin<T> on NotifyManager<T> { | @@ -96,10 +97,11 @@ mixin RxObjectMixin<T> on NotifyManager<T> { | ||
96 | /// Widget, only if it's different from the previous value. | 97 | /// Widget, only if it's different from the previous value. |
97 | set value(T val) { | 98 | set value(T val) { |
98 | if (subject.isClosed) return; | 99 | if (subject.isClosed) return; |
100 | + sentToStream = false; | ||
99 | if (_value == val && !firstRebuild) return; | 101 | if (_value == val && !firstRebuild) return; |
100 | firstRebuild = false; | 102 | firstRebuild = false; |
101 | _value = val; | 103 | _value = val; |
102 | - | 104 | + sentToStream = true; |
103 | subject.add(_value); | 105 | subject.add(_value); |
104 | } | 106 | } |
105 | 107 | ||
@@ -254,7 +256,7 @@ abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> { | @@ -254,7 +256,7 @@ abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> { | ||
254 | value = v; | 256 | value = v; |
255 | // If it's not the first rebuild, the listeners have been called already | 257 | // If it's not the first rebuild, the listeners have been called already |
256 | // So we won't call them again. | 258 | // So we won't call them again. |
257 | - if (!firstRebuild) { | 259 | + if (!firstRebuild && !sentToStream) { |
258 | subject.add(v); | 260 | subject.add(v); |
259 | } | 261 | } |
260 | } | 262 | } |
@@ -36,13 +36,13 @@ mixin GetSingleTickerProviderStateMixin on GetxController | @@ -36,13 +36,13 @@ mixin GetSingleTickerProviderStateMixin on GetxController | ||
36 | if (_ticker == null) return true; | 36 | if (_ticker == null) return true; |
37 | throw FlutterError.fromParts(<DiagnosticsNode>[ | 37 | throw FlutterError.fromParts(<DiagnosticsNode>[ |
38 | ErrorSummary( | 38 | ErrorSummary( |
39 | - '$runtimeType is a SingleTickerProviderStateMixin but multiple tickers were created.'), | 39 | + '$runtimeType is a GetSingleTickerProviderStateMixin but multiple tickers were created.'), |
40 | ErrorDescription( | 40 | ErrorDescription( |
41 | - 'A SingleTickerProviderStateMixin can only be used as a TickerProvider once.'), | 41 | + 'A GetSingleTickerProviderStateMixin can only be used as a TickerProvider once.'), |
42 | ErrorHint( | 42 | ErrorHint( |
43 | 'If a State is used for multiple AnimationController objects, or if it is passed to other ' | 43 | 'If a State is used for multiple AnimationController objects, or if it is passed to other ' |
44 | 'objects and those objects might use it more than one time in total, then instead of ' | 44 | 'objects and those objects might use it more than one time in total, then instead of ' |
45 | - 'mixing in a SingleTickerProviderStateMixin, use a regular TickerProviderStateMixin.', | 45 | + 'mixing in a GetSingleTickerProviderStateMixin, use a regular GetTickerProviderStateMixin.', |
46 | ), | 46 | ), |
47 | ]); | 47 | ]); |
48 | }()); | 48 | }()); |
@@ -66,7 +66,7 @@ mixin GetSingleTickerProviderStateMixin on GetxController | @@ -66,7 +66,7 @@ mixin GetSingleTickerProviderStateMixin on GetxController | ||
66 | throw FlutterError.fromParts(<DiagnosticsNode>[ | 66 | throw FlutterError.fromParts(<DiagnosticsNode>[ |
67 | ErrorSummary('$this was disposed with an active Ticker.'), | 67 | ErrorSummary('$this was disposed with an active Ticker.'), |
68 | ErrorDescription( | 68 | ErrorDescription( |
69 | - '$runtimeType created a Ticker via its SingleTickerProviderStateMixin, but at the time ' | 69 | + '$runtimeType created a Ticker via its GetSingleTickerProviderStateMixin, but at the time ' |
70 | 'dispose() was called on the mixin, that Ticker was still active. The Ticker must ' | 70 | 'dispose() was called on the mixin, that Ticker was still active. The Ticker must ' |
71 | 'be disposed before calling super.dispose().', | 71 | 'be disposed before calling super.dispose().', |
72 | ), | 72 | ), |
@@ -82,6 +82,99 @@ mixin GetSingleTickerProviderStateMixin on GetxController | @@ -82,6 +82,99 @@ mixin GetSingleTickerProviderStateMixin on GetxController | ||
82 | } | 82 | } |
83 | } | 83 | } |
84 | 84 | ||
85 | +/// Used like `TickerProviderMixin` but only with Get Controllers. | ||
86 | +/// Simplifies multiple AnimationController creation inside GetxController. | ||
87 | +/// | ||
88 | +/// Example: | ||
89 | +///``` | ||
90 | +///class SplashController extends GetxController with | ||
91 | +/// GetTickerProviderStateMixin { | ||
92 | +/// AnimationController first_controller; | ||
93 | +/// AnimationController second_controller; | ||
94 | +/// | ||
95 | +/// @override | ||
96 | +/// void onInit() { | ||
97 | +/// final duration = const Duration(seconds: 2); | ||
98 | +/// first_controller = | ||
99 | +/// AnimationController.unbounded(duration: duration, vsync: this); | ||
100 | +/// second_controller = | ||
101 | +/// AnimationController.unbounded(duration: duration, vsync: this); | ||
102 | +/// first_controller.repeat(); | ||
103 | +/// first_controller.addListener(() => | ||
104 | +/// print("Animation Controller value: ${first_controller.value}")); | ||
105 | +/// second_controller.addListener(() => | ||
106 | +/// print("Animation Controller value: ${second_controller.value}")); | ||
107 | +/// } | ||
108 | +/// ... | ||
109 | +/// ``` | ||
110 | +mixin GetTickerProviderStateMixin on GetxController implements TickerProvider { | ||
111 | + Set<Ticker>? _tickers; | ||
112 | + | ||
113 | + @override | ||
114 | + Ticker createTicker(TickerCallback onTick) { | ||
115 | + _tickers ??= <_WidgetTicker>{}; | ||
116 | + final result = _WidgetTicker(onTick, this, debugLabel: kDebugMode ? 'created by ${describeIdentity(this)}' : null); | ||
117 | + _tickers!.add(result); | ||
118 | + return result; | ||
119 | + } | ||
120 | + | ||
121 | + void _removeTicker(_WidgetTicker ticker) { | ||
122 | + assert(_tickers != null); | ||
123 | + assert(_tickers!.contains(ticker)); | ||
124 | + _tickers!.remove(ticker); | ||
125 | + } | ||
126 | + | ||
127 | + void didChangeDependencies(BuildContext context) { | ||
128 | + final muted = !TickerMode.of(context); | ||
129 | + if (_tickers != null) { | ||
130 | + for (final ticker in _tickers!) { | ||
131 | + ticker.muted = muted; | ||
132 | + } | ||
133 | + } | ||
134 | + } | ||
135 | + | ||
136 | + @override | ||
137 | + void onClose() { | ||
138 | + assert(() { | ||
139 | + if (_tickers != null) { | ||
140 | + for (final ticker in _tickers!) { | ||
141 | + if (ticker.isActive) { | ||
142 | + throw FlutterError.fromParts(<DiagnosticsNode>[ | ||
143 | + ErrorSummary('$this was disposed with an active Ticker.'), | ||
144 | + ErrorDescription( | ||
145 | + '$runtimeType created a Ticker via its GetTickerProviderStateMixin, but at the time ' | ||
146 | + 'dispose() was called on the mixin, that Ticker was still active. All Tickers must ' | ||
147 | + 'be disposed before calling super.dispose().', | ||
148 | + ), | ||
149 | + ErrorHint( | ||
150 | + 'Tickers used by AnimationControllers ' | ||
151 | + 'should be disposed by calling dispose() on the AnimationController itself. ' | ||
152 | + 'Otherwise, the ticker will leak.', | ||
153 | + ), | ||
154 | + ticker.describeForError('The offending ticker was'), | ||
155 | + ]); | ||
156 | + } | ||
157 | + } | ||
158 | + } | ||
159 | + return true; | ||
160 | + }()); | ||
161 | + super.onClose(); | ||
162 | + } | ||
163 | + | ||
164 | +} | ||
165 | + | ||
166 | +class _WidgetTicker extends Ticker { | ||
167 | + _WidgetTicker(TickerCallback onTick, this._creator, { String? debugLabel }) : super(onTick, debugLabel: debugLabel); | ||
168 | + | ||
169 | + final GetTickerProviderStateMixin _creator; | ||
170 | + | ||
171 | + @override | ||
172 | + void dispose() { | ||
173 | + _creator._removeTicker(this); | ||
174 | + super.dispose(); | ||
175 | + } | ||
176 | +} | ||
177 | + | ||
85 | @Deprecated('use GetSingleTickerProviderStateMixin') | 178 | @Deprecated('use GetSingleTickerProviderStateMixin') |
86 | 179 | ||
87 | /// Used like `SingleTickerProviderMixin` but only with Get Controllers. | 180 | /// Used like `SingleTickerProviderMixin` but only with Get Controllers. |
@@ -69,13 +69,13 @@ extension Trans on String { | @@ -69,13 +69,13 @@ extension Trans on String { | ||
69 | final translationsWithNoCountry = Get.translations | 69 | final translationsWithNoCountry = Get.translations |
70 | .map((key, value) => MapEntry(key.split("_").first, value)); | 70 | .map((key, value) => MapEntry(key.split("_").first, value)); |
71 | final containsKey = | 71 | final containsKey = |
72 | - translationsWithNoCountry.containsKey(Get.locale!.languageCode); | 72 | + translationsWithNoCountry.containsKey(Get.locale!.languageCode.split("_").first); |
73 | 73 | ||
74 | if (!containsKey) { | 74 | if (!containsKey) { |
75 | return null; | 75 | return null; |
76 | } | 76 | } |
77 | 77 | ||
78 | - return translationsWithNoCountry[Get.locale!.languageCode]; | 78 | + return translationsWithNoCountry[Get.locale!.languageCode.split("_").first]; |
79 | } | 79 | } |
80 | 80 | ||
81 | String get tr { | 81 | String get tr { |
@@ -125,7 +125,7 @@ void main() { | @@ -125,7 +125,7 @@ void main() { | ||
125 | reactiveInteger.trigger(3); | 125 | reactiveInteger.trigger(3); |
126 | // then repeat twice | 126 | // then repeat twice |
127 | reactiveInteger.trigger(3); | 127 | reactiveInteger.trigger(3); |
128 | - reactiveInteger.trigger(3); | 128 | + reactiveInteger.trigger(1); |
129 | 129 | ||
130 | await Future.delayed(Duration(milliseconds: 100)); | 130 | await Future.delayed(Duration(milliseconds: 100)); |
131 | expect(3, timesCalled); | 131 | expect(3, timesCalled); |
-
Please register or login to post a comment