feat: Phase 2 — upgrade deps to null-safe, replace deprecated packages
- pubspec: bump all maintained deps to null-safe latest; flutter pub get resolves
- Remove 12 packages (0-ref or no null-safe): splashscreen, flappy_search_bar,
searchable_dropdown, share, platform_detect, flutter_inappwebview, countdown,
gender_selection, flutter_dash, smooth_star_rating, hovering, ffi
- Add flutter_rating_bar
- Keep discontinued-but-null-safe for now (Phase 5): pull_to_refresh, hive, catcher
- New null-safe custom components (API-compatible, callers change only imports):
utils/countdown.dart, widgets/general/{hover_widget,gender_selection,
smooth_star_rating,search_bar}.dart
- main.dart: drop dead SplashScreen _buildBody + _to field
- 23 consuming files: swap deprecated imports to local components
Null-safety migration + upgraded-API adaptation = Phase 3.
This commit is contained in:
@@ -15,7 +15,7 @@
|
|||||||
## 阶段
|
## 阶段
|
||||||
- [x] 阶段 0:基线 & 锁版本
|
- [x] 阶段 0:基线 & 锁版本
|
||||||
- [x] 阶段 1:去掉 Stripe
|
- [x] 阶段 1:去掉 Stripe
|
||||||
- [ ] 阶段 2:依赖替换与升级
|
- [x] 阶段 2:依赖替换与升级
|
||||||
- [ ] 阶段 3:空安全迁移
|
- [ ] 阶段 3:空安全迁移
|
||||||
- [ ] 阶段 4:Web 跑起来
|
- [ ] 阶段 4:Web 跑起来
|
||||||
|
|
||||||
@@ -38,3 +38,18 @@
|
|||||||
- constants.dart: 新增 ETRANSFER_EMAIL(payment@wisetronic.com) 与 REMARK_PREFIX(R#)
|
- constants.dart: 新增 ETRANSFER_EMAIL(payment@wisetronic.com) 与 REMARK_PREFIX(R#)
|
||||||
- 新增 lib/widgets/general/e_transfer_pay.dart: 展示邮箱 + 提醒备注写 R#<orderId>
|
- 新增 lib/widgets/general/e_transfer_pay.dart: 展示邮箱 + 提醒备注写 R#<orderId>
|
||||||
- 保留: PAYMENT_METHOD_CODE_STRIPE='stripe'(API 仍返回该 code,路由到 e-Transfer);payment_platform.dart 的 'stripe' 显示名(后续美化时调整)
|
- 保留: PAYMENT_METHOD_CODE_STRIPE='stripe'(API 仍返回该 code,路由到 e-Transfer);payment_platform.dart 的 'stripe' 显示名(后续美化时调整)
|
||||||
|
|
||||||
|
### 阶段 2 — 依赖替换与升级(已完成)
|
||||||
|
**flutter pub get 成功解析 178 个依赖。**
|
||||||
|
- 升级到 null-safe 最新版:dio ^5.7、cached_network_image ^3.4、url_launcher ^6.3、path_provider ^2.1、image_picker ^1.1、google_maps_flutter ^2.9、geolocator ^12、youtube_player_iframe ^5.2、flutter_local_notifications ^17、uuid ^4、fluttertoast ^8.2、badges ^3、carousel_slider ^5、percent_indicator ^4.2.3、photo_view ^0.15、toggle_switch ^2.3、pinput ^5、email_validator ^3、responsive_builder ^0.7、flutter_redux ^0.10、fluro ^2.0.5、font_awesome_flutter ^10、flutter_spinkit ^5.2、flutter_markdown ^0.7、url_strategy ^0.3、universal_io/html
|
||||||
|
- 删除(0引用或无 null-safe 版):splashscreen(死代码)、flappy_search_bar、searchable_dropdown、share、platform_detect、flutter_inappwebview、countdown、gender_selection、flutter_dash(死 import)、smooth_star_rating、hovering、ffi
|
||||||
|
- 新增:flutter_rating_bar ^4.0
|
||||||
|
- 停维但有 null-safe 版→暂留(Phase 5 再换):pull_to_refresh(→smart_refresher)、hive/hive_flutter(→hive_ce)、catcher ^0.8(→catcher2)
|
||||||
|
- 新建 null-safe 自定义组件替代废弃包(API 兼容, 调用方仅改 import):
|
||||||
|
- lib/utils/countdown.dart (CountDown.stream)
|
||||||
|
- lib/widgets/general/hover_widget.dart (HoverWidget)
|
||||||
|
- lib/widgets/general/gender_selection.dart (Gender 枚举 + GenderSelection)
|
||||||
|
- lib/widgets/general/smooth_star_rating.dart (SmoothStarRating)
|
||||||
|
- lib/widgets/general/search_bar.dart (轻量 Web 搜索 SearchBar + SearchBarController, 含 replayLastSearch 分页)
|
||||||
|
- main.dart:删除未使用的 _buildBody(SplashScreen) 与 _to 字段
|
||||||
|
- ⚠️ 待 Phase 3:API 升级破坏性变更(dio5/badges3/toggle_switch2/pinput5/geolocator12 等用法适配) + 整库空安全迁移,按 dart analyze 驱动修复
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import 'pages/create_online_store_1.dart';
|
|||||||
import 'pages/download.dart';
|
import 'pages/download.dart';
|
||||||
import 'pages/me.dart';
|
import 'pages/me.dart';
|
||||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||||
import 'package:splashscreen/splashscreen.dart';
|
|
||||||
// import 'package:uni_links/uni_links.dart';
|
// import 'package:uni_links/uni_links.dart';
|
||||||
|
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
@@ -41,8 +40,6 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
String _to = '/';
|
|
||||||
|
|
||||||
MyApp() {
|
MyApp() {
|
||||||
Routes.configure();
|
Routes.configure();
|
||||||
Utils().init();
|
Utils().init();
|
||||||
@@ -95,24 +92,6 @@ class MyApp extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
Widget _buildBody() {
|
|
||||||
return SplashScreen(
|
|
||||||
seconds: 5,
|
|
||||||
routeName: _to,
|
|
||||||
navigateAfterSeconds: Home(title: Constants.APP_TITLE,),
|
|
||||||
styleTextUnderTheLoader: new TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 20.0,
|
|
||||||
),
|
|
||||||
imageBackground: (Image.network(Constants.BASE_API_URL + 'gallery/get-minimanager-splash/')).image,
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
onClick: () {
|
|
||||||
|
|
||||||
},
|
|
||||||
loaderColor: Colors.blue,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
debugShowCheckedModeBanner: Constants.DEBUG,
|
debugShowCheckedModeBanner: Constants.DEBUG,
|
||||||
navigatorKey: kIsWeb ? null : Catcher.navigatorKey,
|
navigatorKey: kIsWeb ? null : Catcher.navigatorKey,
|
||||||
|
|||||||
29
lib/utils/countdown.dart
Normal file
29
lib/utils/countdown.dart
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
/// 自定义实现,替代已停维的 `countdown` 包的 [CountDown]。
|
||||||
|
///
|
||||||
|
/// 用法与原包兼容:
|
||||||
|
/// ```dart
|
||||||
|
/// var listener = CountDown(Duration(seconds: 90)).stream.listen(null);
|
||||||
|
/// listener.onData((Duration d) { ... d.inSeconds ... });
|
||||||
|
/// listener.onDone(() { ... });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// `stream` 每秒发出剩余 [Duration](从满时长倒数到 0),到达 0 后关闭。
|
||||||
|
class CountDown {
|
||||||
|
CountDown(this.duration) : assert(!duration.isNegative);
|
||||||
|
|
||||||
|
final Duration duration;
|
||||||
|
|
||||||
|
Stream<Duration> get stream => _countdownStream();
|
||||||
|
|
||||||
|
Stream<Duration> _countdownStream() async* {
|
||||||
|
int remaining = duration.inSeconds;
|
||||||
|
while (remaining > 0) {
|
||||||
|
yield Duration(seconds: remaining);
|
||||||
|
await Future<void>.delayed(const Duration(seconds: 1));
|
||||||
|
remaining--;
|
||||||
|
}
|
||||||
|
yield Duration.zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
import 'package:countdown/countdown.dart';
|
import '../../utils/countdown.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||||
import 'package:flutter_wisetronic/widgets/general/breadcrumbs.dart';
|
import 'package:flutter_wisetronic/widgets/general/breadcrumbs.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:gender_selection/gender_selection.dart';
|
import '../general/gender_selection.dart';
|
||||||
|
|
||||||
import '../../constants.dart';
|
import '../../constants.dart';
|
||||||
import '../../events/eventbus.dart';
|
import '../../events/eventbus.dart';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
import 'package:countdown/countdown.dart';
|
import '../../utils/countdown.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter_wisetronic/widgets/general/breadcrumbs.dart';
|
import 'package:flutter_wisetronic/widgets/general/breadcrumbs.dart';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import 'package:email_validator/email_validator.dart';
|
import 'package:email_validator/email_validator.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_wisetronic/widgets/general/breadcrumbs.dart';
|
import 'package:flutter_wisetronic/widgets/general/breadcrumbs.dart';
|
||||||
import 'package:gender_selection/gender_selection.dart';
|
import '../general/gender_selection.dart';
|
||||||
|
|
||||||
import '../../constants.dart';
|
import '../../constants.dart';
|
||||||
import '../../generated/l10n.dart';
|
import '../../generated/l10n.dart';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_wisetronic/widgets/general/breadcrumbs.dart';
|
import 'package:flutter_wisetronic/widgets/general/breadcrumbs.dart';
|
||||||
import 'package:flutter_wisetronic/widgets/general/navigationbar.dart';
|
import 'package:flutter_wisetronic/widgets/general/navigationbar.dart';
|
||||||
import 'package:percent_indicator/linear_percent_indicator.dart';
|
import 'package:percent_indicator/linear_percent_indicator.dart';
|
||||||
import 'package:smooth_star_rating/smooth_star_rating.dart';
|
import '../general/smooth_star_rating.dart';
|
||||||
|
|
||||||
import '../../constants.dart';
|
import '../../constants.dart';
|
||||||
import '../../events/eventbus.dart';
|
import '../../events/eventbus.dart';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
import 'package:countdown/countdown.dart';
|
import '../../utils/countdown.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flappy_search_bar/flappy_search_bar.dart';
|
import '../general/search_bar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_wisetronic/widgets/general/breadcrumbs.dart';
|
import 'package:flutter_wisetronic/widgets/general/breadcrumbs.dart';
|
||||||
import 'package:flutter_wisetronic/widgets/general/navigationbar.dart';
|
import 'package:flutter_wisetronic/widgets/general/navigationbar.dart';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flappy_search_bar/flappy_search_bar.dart';
|
import '../general/search_bar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter_wisetronic/pages/product_detail_page.dart';
|
import 'package:flutter_wisetronic/pages/product_detail_page.dart';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hovering/hovering.dart';
|
import '../general/hover_widget.dart';
|
||||||
|
|
||||||
import '../../events/eventbus.dart';
|
import '../../events/eventbus.dart';
|
||||||
import '../../events/events.dart';
|
import '../../events/events.dart';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flappy_search_bar/flappy_search_bar.dart';
|
import '../general/search_bar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../constants.dart';
|
import '../../constants.dart';
|
||||||
|
|||||||
111
lib/widgets/general/gender_selection.dart
Normal file
111
lib/widgets/general/gender_selection.dart
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// 自定义实现,替代已停维的 `gender_selection` 包。
|
||||||
|
///
|
||||||
|
/// 保留原 `Gender` 枚举与 `GenderSelection` 组件的命名参数,
|
||||||
|
/// 使调用方仅改 import 即可编译。大部分装饰性参数为兼容保留(暂未全部生效,
|
||||||
|
/// 后续美化阶段 Phase 5 再完善视觉)。
|
||||||
|
enum Gender { Male, Female }
|
||||||
|
|
||||||
|
class GenderSelection extends StatefulWidget {
|
||||||
|
final String? maleText;
|
||||||
|
final String? femaleText;
|
||||||
|
final Color? selectedGenderIconBackgroundColor;
|
||||||
|
final Alignment? checkIconAlignment;
|
||||||
|
final IconData? selectedGenderCheckIcon;
|
||||||
|
final void Function(Gender gender)? onChanged;
|
||||||
|
final bool? equallyAligned;
|
||||||
|
final Duration? animationDuration;
|
||||||
|
final bool? isCircular;
|
||||||
|
final bool? isSelectedGenderIconCircular;
|
||||||
|
final double? opacityOfGradient;
|
||||||
|
final EdgeInsets? padding;
|
||||||
|
final double? size;
|
||||||
|
final Gender? selectedGender;
|
||||||
|
|
||||||
|
const GenderSelection({
|
||||||
|
super.key,
|
||||||
|
this.maleText,
|
||||||
|
this.femaleText,
|
||||||
|
this.selectedGenderIconBackgroundColor,
|
||||||
|
this.checkIconAlignment,
|
||||||
|
this.selectedGenderCheckIcon,
|
||||||
|
this.onChanged,
|
||||||
|
this.equallyAligned,
|
||||||
|
this.animationDuration,
|
||||||
|
this.isCircular,
|
||||||
|
this.isSelectedGenderIconCircular,
|
||||||
|
this.opacityOfGradient,
|
||||||
|
this.padding,
|
||||||
|
this.size,
|
||||||
|
this.selectedGender,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<GenderSelection> createState() => _GenderSelectionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GenderSelectionState extends State<GenderSelection> {
|
||||||
|
Gender? _selected;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_selected = widget.selectedGender;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildOption(Gender gender, String label) {
|
||||||
|
final selected = _selected == gender;
|
||||||
|
final color = widget.selectedGenderIconBackgroundColor ?? Colors.indigo;
|
||||||
|
return Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: widget.padding ?? const EdgeInsets.all(3.0),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
setState(() => _selected = gender);
|
||||||
|
widget.onChanged?.call(gender);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
height: widget.size ?? 50.0,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: selected ? color : color.withOpacity(0.06),
|
||||||
|
borderRadius:
|
||||||
|
(widget.isCircular ?? false) ? BorderRadius.circular(60) : null,
|
||||||
|
border: Border.all(
|
||||||
|
color: selected ? color : Colors.black26,
|
||||||
|
width: selected ? 2 : 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
if (selected && widget.selectedGenderCheckIcon != null)
|
||||||
|
Icon(widget.selectedGenderCheckIcon, color: Colors.white, size: 18),
|
||||||
|
if (selected && widget.selectedGenderCheckIcon != null)
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
color: selected ? Colors.white : Colors.black87,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
children: <Widget>[
|
||||||
|
_buildOption(Gender.Male, widget.maleText ?? 'Mr'),
|
||||||
|
_buildOption(Gender.Female, widget.femaleText ?? 'Ms'),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
lib/widgets/general/hover_widget.dart
Normal file
46
lib/widgets/general/hover_widget.dart
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// 自定义实现,替代已停维的 `hovering` 包的 [HoverWidget]。
|
||||||
|
///
|
||||||
|
/// API 兼容:
|
||||||
|
/// ```dart
|
||||||
|
/// HoverWidget(
|
||||||
|
/// child: ...,
|
||||||
|
/// hoverChild: ...,
|
||||||
|
/// onHover: (PointerHoverEvent event) { ... },
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// 鼠标悬停时显示 [hoverChild],否则显示 [child]。
|
||||||
|
class HoverWidget extends StatefulWidget {
|
||||||
|
final Widget child;
|
||||||
|
final Widget? hoverChild;
|
||||||
|
final void Function(PointerHoverEvent)? onHover;
|
||||||
|
|
||||||
|
const HoverWidget({
|
||||||
|
super.key,
|
||||||
|
required this.child,
|
||||||
|
this.hoverChild,
|
||||||
|
this.onHover,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HoverWidget> createState() => _HoverWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HoverWidgetState extends State<HoverWidget> {
|
||||||
|
bool _hovering = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MouseRegion(
|
||||||
|
cursor: SystemMouseCursors.click,
|
||||||
|
onHover: widget.onHover,
|
||||||
|
onEnter: (_) => setState(() => _hovering = true),
|
||||||
|
onExit: (_) => setState(() => _hovering = false),
|
||||||
|
child: (_hovering && widget.hoverChild != null)
|
||||||
|
? widget.hoverChild!
|
||||||
|
: widget.child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
import 'package:countdown/countdown.dart';
|
import '../utils/countdown.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:pinput/pin_put/pin_put.dart';
|
import 'package:pinput/pin_put/pin_put.dart';
|
||||||
|
|
||||||
|
|||||||
185
lib/widgets/general/search_bar.dart
Normal file
185
lib/widgets/general/search_bar.dart
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// 轻量级异步搜索控制器,配合 [SearchBar] 使用。
|
||||||
|
///
|
||||||
|
/// 替代已停维的 `flappy_search_bar` 的 `SearchBarController`。
|
||||||
|
/// 保留泛型 `<T>` 以兼容调用方 `SearchBarController<Product>()` 写法。
|
||||||
|
/// [replayLastSearch] 用于“加载更多 / 分页”:外部 page++ 后触发重跑上一次搜索。
|
||||||
|
class SearchBarController<T> {
|
||||||
|
String lastQuery = '';
|
||||||
|
VoidCallback? _replay;
|
||||||
|
|
||||||
|
void _register(VoidCallback replay) {
|
||||||
|
_replay = replay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 重新执行上一次搜索(分页加载更多时调用)。
|
||||||
|
void replayLastSearch() => _replay?.call();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 轻量级 Web 异步搜索栏,替代已停维的 `flappy_search_bar` 的 `SearchBar`。
|
||||||
|
///
|
||||||
|
/// 基本流程:输入达到 [minimumChars] 个字符后,调用 [onSearch] 取结果,
|
||||||
|
/// 用 [onItemFound] 渲染每一条;无结果时显示 [emptyWidget];出错显示 [onError]。
|
||||||
|
///
|
||||||
|
/// 注意:`searchBarController` 参数刻意使用裸类型(`SearchBarController?`),
|
||||||
|
/// 以兼容调用方 `SearchBarController _controller = SearchBarController<Product>();`
|
||||||
|
/// 的写法(Dart 3 sound 类型下避免泛型不变性报错)。
|
||||||
|
class SearchBar<T> extends StatefulWidget {
|
||||||
|
final SearchBarController? searchBarController;
|
||||||
|
final int minimumChars;
|
||||||
|
final String? hintText;
|
||||||
|
final Widget? cancellationWidget;
|
||||||
|
final Future<List<T>> Function(String text) onSearch;
|
||||||
|
final Widget Function(T item, int index) onItemFound;
|
||||||
|
final Widget Function(dynamic error)? onError;
|
||||||
|
final Widget? emptyWidget;
|
||||||
|
final Duration debounceDuration;
|
||||||
|
|
||||||
|
const SearchBar({
|
||||||
|
super.key,
|
||||||
|
this.searchBarController,
|
||||||
|
this.minimumChars = 2,
|
||||||
|
this.hintText,
|
||||||
|
this.cancellationWidget,
|
||||||
|
required this.onSearch,
|
||||||
|
required this.onItemFound,
|
||||||
|
this.onError,
|
||||||
|
this.emptyWidget,
|
||||||
|
this.debounceDuration = const Duration(milliseconds: 350),
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SearchBar<T>> createState() => _SearchBarState<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SearchBarState<T> extends State<SearchBar<T>> {
|
||||||
|
final TextEditingController _textController = TextEditingController();
|
||||||
|
final FocusNode _focusNode = FocusNode();
|
||||||
|
Timer? _debounce;
|
||||||
|
List<T> _results = <T>[];
|
||||||
|
bool _loading = false;
|
||||||
|
dynamic _error;
|
||||||
|
bool _hasSearched = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
widget.searchBarController?._register(_runSearch);
|
||||||
|
_textController.addListener(_onTextChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_debounce?.cancel();
|
||||||
|
_textController.dispose();
|
||||||
|
_focusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onTextChanged() {
|
||||||
|
final text = _textController.text;
|
||||||
|
_debounce?.cancel();
|
||||||
|
if (text.length >= widget.minimumChars) {
|
||||||
|
_debounce = Timer(widget.debounceDuration, _runSearch);
|
||||||
|
} else if (text.isEmpty) {
|
||||||
|
setState(() {
|
||||||
|
_results = <T>[];
|
||||||
|
_hasSearched = false;
|
||||||
|
_error = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _runSearch() async {
|
||||||
|
final query = _textController.text;
|
||||||
|
if (query.length < widget.minimumChars) return;
|
||||||
|
if (widget.searchBarController != null) {
|
||||||
|
widget.searchBarController!.lastQuery = query;
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
_loading = true;
|
||||||
|
_error = null;
|
||||||
|
_hasSearched = true;
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
final results = await widget.onSearch(query);
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_results = results;
|
||||||
|
_loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_error = e;
|
||||||
|
_loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _cancel() {
|
||||||
|
_textController.clear();
|
||||||
|
_focusNode.unfocus();
|
||||||
|
setState(() {
|
||||||
|
_results = <T>[];
|
||||||
|
_hasSearched = false;
|
||||||
|
_error = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: <Widget>[
|
||||||
|
TextField(
|
||||||
|
controller: _textController,
|
||||||
|
focusNode: _focusNode,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: widget.hintText,
|
||||||
|
prefixIcon: const Icon(Icons.search),
|
||||||
|
suffixIcon: _textController.text.isNotEmpty
|
||||||
|
? GestureDetector(
|
||||||
|
onTap: _cancel,
|
||||||
|
child: widget.cancellationWidget ??
|
||||||
|
const Icon(Icons.close, size: 20),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Expanded(child: _buildBody()),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildBody() {
|
||||||
|
if (_loading) {
|
||||||
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
if (_error != null) {
|
||||||
|
return widget.onError != null
|
||||||
|
? widget.onError!(_error)
|
||||||
|
: Center(child: Text('$_error'));
|
||||||
|
}
|
||||||
|
if (!_hasSearched) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
if (_results.isEmpty) {
|
||||||
|
return widget.emptyWidget ?? const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: _results.length,
|
||||||
|
itemBuilder: (BuildContext context, int index) =>
|
||||||
|
widget.onItemFound(_results[index], index),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
90
lib/widgets/general/smooth_star_rating.dart
Normal file
90
lib/widgets/general/smooth_star_rating.dart
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// 自定义实现,替代已停维的 `smooth_star_rating` 包的 [SmoothStarRating]。
|
||||||
|
///
|
||||||
|
/// 保留原命名参数(`allowHalfRating`/`onRated`/`starCount`/`rating`/`size`/
|
||||||
|
/// `filledIconData`/`color`/`borderColor`/`spacing`),调用方仅改 import 即可。
|
||||||
|
class SmoothStarRating extends StatefulWidget {
|
||||||
|
final bool allowHalfRating;
|
||||||
|
final void Function(double)? onRated;
|
||||||
|
final int starCount;
|
||||||
|
final double rating;
|
||||||
|
final double size;
|
||||||
|
final IconData filledIconData;
|
||||||
|
final IconData? halfFilledIconData;
|
||||||
|
final IconData? defaultIconData;
|
||||||
|
final Color color;
|
||||||
|
final Color borderColor;
|
||||||
|
final double spacing;
|
||||||
|
|
||||||
|
const SmoothStarRating({
|
||||||
|
super.key,
|
||||||
|
this.allowHalfRating = false,
|
||||||
|
this.onRated,
|
||||||
|
this.starCount = 5,
|
||||||
|
this.rating = 0.0,
|
||||||
|
this.size = 24.0,
|
||||||
|
this.filledIconData = Icons.star,
|
||||||
|
this.halfFilledIconData,
|
||||||
|
this.defaultIconData,
|
||||||
|
this.color = Colors.orange,
|
||||||
|
this.borderColor = Colors.orange,
|
||||||
|
this.spacing = 0.0,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SmoothStarRating> createState() => _SmoothStarRatingState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SmoothStarRatingState extends State<SmoothStarRating> {
|
||||||
|
late double _rating;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_rating = widget.rating;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(covariant SmoothStarRating oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (oldWidget.rating != widget.rating) {
|
||||||
|
_rating = widget.rating;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _star(int index) {
|
||||||
|
IconData icon;
|
||||||
|
Color iconColor;
|
||||||
|
if (index < _rating.floor()) {
|
||||||
|
icon = widget.filledIconData;
|
||||||
|
iconColor = widget.color;
|
||||||
|
} else if (widget.allowHalfRating &&
|
||||||
|
index == _rating.floor() &&
|
||||||
|
(_rating - index) >= 0.5) {
|
||||||
|
icon = widget.halfFilledIconData ?? Icons.star_half;
|
||||||
|
iconColor = widget.color;
|
||||||
|
} else {
|
||||||
|
icon = widget.defaultIconData ?? Icons.star_border;
|
||||||
|
iconColor = widget.borderColor;
|
||||||
|
}
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() => _rating = (index + 1).toDouble());
|
||||||
|
widget.onRated?.call(_rating);
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: widget.spacing / 2),
|
||||||
|
child: Icon(icon, size: widget.size, color: iconColor),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: List<Widget>.generate(widget.starCount, _star),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import 'package:fluro/fluro.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter_wisetronic/utils/utils.dart';
|
import 'package:flutter_wisetronic/utils/utils.dart';
|
||||||
import 'package:hovering/hovering.dart';
|
import 'hover_widget.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
import '../../routes.dart';
|
import '../../routes.dart';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
import 'package:countdown/countdown.dart';
|
import '../../utils/countdown.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import 'package:flutter_wisetronic/store/store.dart';
|
|||||||
import 'package:flutter_wisetronic/utils/http_util.dart';
|
import 'package:flutter_wisetronic/utils/http_util.dart';
|
||||||
import 'package:flutter_wisetronic/utils/utils.dart';
|
import 'package:flutter_wisetronic/utils/utils.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:gender_selection/gender_selection.dart';
|
import '../general/gender_selection.dart';
|
||||||
|
|
||||||
import '../../routes.dart';
|
import '../../routes.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
import 'package:countdown/countdown.dart';
|
import '../../utils/countdown.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import 'package:email_validator/email_validator.dart';
|
import 'package:email_validator/email_validator.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gender_selection/gender_selection.dart';
|
import '../general/gender_selection.dart';
|
||||||
|
|
||||||
import '../../generated/l10n.dart';
|
import '../../generated/l10n.dart';
|
||||||
import '../../models/located_address.dart';
|
import '../../models/located_address.dart';
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import 'package:badges/badges.dart';
|
import 'package:badges/badges.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:percent_indicator/linear_percent_indicator.dart';
|
import 'package:percent_indicator/linear_percent_indicator.dart';
|
||||||
import 'package:smooth_star_rating/smooth_star_rating.dart';
|
import '../general/smooth_star_rating.dart';
|
||||||
|
|
||||||
import '../../events/eventbus.dart';
|
import '../../events/eventbus.dart';
|
||||||
import '../../events/events.dart';
|
import '../../events/events.dart';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
import 'package:countdown/countdown.dart';
|
import '../../utils/countdown.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flappy_search_bar/flappy_search_bar.dart';
|
import '../general/search_bar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../events/eventbus.dart';
|
import '../../events/eventbus.dart';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flappy_search_bar/flappy_search_bar.dart';
|
import '../general/search_bar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../events/eventbus.dart';
|
import '../../events/eventbus.dart';
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
|
||||||
import 'package:badges/badges.dart';
|
import 'package:badges/badges.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_dash/flutter_dash.dart';
|
|
||||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||||
import 'package:flutter_wisetronic/dialog/image_viewer.dart';
|
import 'package:flutter_wisetronic/dialog/image_viewer.dart';
|
||||||
import 'package:flutter_wisetronic/events/eventbus.dart';
|
import 'package:flutter_wisetronic/events/eventbus.dart';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flappy_search_bar/flappy_search_bar.dart';
|
import '../general/search_bar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../events/eventbus.dart';
|
import '../../events/eventbus.dart';
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import 'package:flutter_wisetronic/widgets/general/read_more_text.dart';
|
|||||||
import 'package:flutter_wisetronic/widgets/general/show_price.dart';
|
import 'package:flutter_wisetronic/widgets/general/show_price.dart';
|
||||||
import 'package:flutter_wisetronic/widgets/general/sliding_up_panel.dart';
|
import 'package:flutter_wisetronic/widgets/general/sliding_up_panel.dart';
|
||||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||||
import 'package:smooth_star_rating/smooth_star_rating.dart';
|
import '../general/smooth_star_rating.dart';
|
||||||
|
|
||||||
import '../../constants.dart';
|
import '../../constants.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,16 @@
|
|||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <catcher/catcher_plugin.h>
|
#include <catcher/catcher_plugin.h>
|
||||||
|
#include <file_selector_linux/file_selector_plugin.h>
|
||||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
g_autoptr(FlPluginRegistrar) catcher_registrar =
|
g_autoptr(FlPluginRegistrar) catcher_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "CatcherPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "CatcherPlugin");
|
||||||
catcher_plugin_register_with_registrar(catcher_registrar);
|
catcher_plugin_register_with_registrar(catcher_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||||
|
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||||
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
catcher
|
catcher
|
||||||
|
file_selector_linux
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,19 +6,25 @@ import FlutterMacOS
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
import catcher
|
import catcher
|
||||||
import device_info_plus_macos
|
import device_info_plus
|
||||||
|
import file_selector_macos
|
||||||
import flutter_local_notifications
|
import flutter_local_notifications
|
||||||
import package_info_plus_macos
|
import geolocator_apple
|
||||||
import path_provider_macos
|
import package_info_plus
|
||||||
import sqflite
|
import path_provider_foundation
|
||||||
|
import sqflite_darwin
|
||||||
import url_launcher_macos
|
import url_launcher_macos
|
||||||
|
import webview_flutter_wkwebview
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
CatcherPlugin.register(with: registry.registrar(forPlugin: "CatcherPlugin"))
|
CatcherPlugin.register(with: registry.registrar(forPlugin: "CatcherPlugin"))
|
||||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||||
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||||
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
||||||
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
|
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
|
||||||
}
|
}
|
||||||
|
|||||||
1103
pubspec.lock
1103
pubspec.lock
File diff suppressed because it is too large
Load Diff
142
pubspec.yaml
142
pubspec.yaml
@@ -2,7 +2,7 @@ name: flutter_wisetronic
|
|||||||
description: Wisetronic website
|
description: Wisetronic website
|
||||||
|
|
||||||
# The following line prevents the package from being accidentally published to
|
# The following line prevents the package from being accidentally published to
|
||||||
# pub.dev using `pub publish`. This is preferred for private packages.
|
# pub.dev using `pub publish -- this is preferred for private packages.
|
||||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||||
|
|
||||||
# The following defines the version and build number for your application.
|
# The following defines the version and build number for your application.
|
||||||
@@ -29,72 +29,60 @@ dependencies:
|
|||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
|
cupertino_icons: ^1.0.8
|
||||||
|
font_awesome_flutter: ^10.8.0
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
responsive_builder: ^0.7.1
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
fluro: ^2.0.5
|
||||||
cupertino_icons: ^1.0.1
|
flutter_redux: ^0.10.0
|
||||||
font_awesome_flutter: ^9.1.0
|
|
||||||
|
|
||||||
responsive_builder: ^0.4.1
|
|
||||||
fluro: ^2.0.3
|
|
||||||
flutter_redux: ^0.8.2
|
|
||||||
event_bus: ^2.0.0
|
event_bus: ^2.0.0
|
||||||
cached_network_image: ^3.1.0 #^2.5.1
|
cached_network_image: ^3.4.1
|
||||||
pull_to_refresh: ^2.0.0 #^1.5.0
|
carousel_slider: ^5.0.0
|
||||||
splashscreen: ^1.3.5
|
badges: ^3.1.2
|
||||||
carousel_slider: ^4.0.0
|
url_launcher: ^6.3.1
|
||||||
badges: ^2.0.1
|
flutter_markdown: ^0.7.4
|
||||||
url_launcher: ^6.1.5 #^6.0.9 #^5.7.10
|
flutter_spinkit: ^5.2.1
|
||||||
# flutter_html: ^2.1.1
|
dio: ^5.7.0
|
||||||
flutter_markdown: ^0.6.4 #^0.5.1
|
email_validator: ^3.0.0
|
||||||
hive: ^2.0.4 #^1.4.4+1
|
path_provider: ^2.1.4
|
||||||
hive_flutter: ^1.1.0 #^0.3.1
|
youtube_player_iframe: ^5.2.0
|
||||||
flutter_spinkit: ^5.0.0
|
fluttertoast: ^8.2.8
|
||||||
dio: ^4.0.0 #^3.0.10
|
percent_indicator: ^4.2.3
|
||||||
searchable_dropdown: ^1.1.3
|
image_picker: ^1.1.2
|
||||||
email_validator: ^2.0.1
|
photo_view: ^0.15.0
|
||||||
flappy_search_bar: ^1.7.2
|
toggle_switch: ^2.3.0
|
||||||
flutter_launcher_icons: ^0.9.1 #^0.8.1
|
pinput: ^5.0.0
|
||||||
# package_info: ^2.0.2
|
google_maps_flutter: ^2.9.0
|
||||||
catcher: ^0.6.8 #^0.4.2
|
uuid: ^4.5.1
|
||||||
share: ^2.0.4 #^0.6.5+4
|
flutter_local_notifications: ^17.2.4
|
||||||
universal_io: ^2.0.4 #^1.0.2
|
geolocator: ^12.0.0
|
||||||
path_provider: ^2.0.2 #^1.6.28
|
url_strategy: ^0.3.0
|
||||||
# path_provider: ^2.0.1
|
universal_io: ^2.2.2
|
||||||
platform_detect: ^2.0.0
|
universal_html: ^2.2.4
|
||||||
flutter_inappwebview: ^5.3.2 #^4.0.0+4
|
|
||||||
youtube_player_iframe: ^2.2.1 #^1.2.0+2
|
|
||||||
fluttertoast: ^8.0.8 #^7.1.8
|
|
||||||
percent_indicator: ^4.2.2 #^3.0.1
|
|
||||||
image_picker: ^0.8.0+3 #^0.6.7+22
|
|
||||||
countdown: ^0.1.0
|
|
||||||
gender_selection: ^1.0.0
|
|
||||||
# uni_links: ^0.5.1 #^0.4.0
|
|
||||||
photo_view: ^0.12.0
|
|
||||||
flutter_dash: ^0.0.1
|
|
||||||
smooth_star_rating: ^1.1.1
|
|
||||||
# tesseract_ocr: ^0.3.1
|
|
||||||
# local_auth: ^1.1.0
|
|
||||||
toggle_switch: ^1.2.0
|
|
||||||
pinput: ^1.2.0
|
|
||||||
google_maps_flutter: ^2.0.6 #^1.2.0
|
|
||||||
# Stripe removed — switched to e-Transfer. See UPGRADE_NOTES.md.
|
|
||||||
uuid: ^3.0.4 #^2.2.2
|
|
||||||
ffi: ^1.0.0
|
|
||||||
# firebase_messaging: ^10.0.4 #^7.0.3
|
|
||||||
flutter_local_notifications: ^8.1.1 #^4.0.1+2
|
|
||||||
geolocator: ^7.4.0 #^6.2.1
|
|
||||||
url_strategy: ^0.2.0
|
|
||||||
hovering: ^1.0.4
|
|
||||||
universal_html: ^2.0.8
|
|
||||||
|
|
||||||
#dev_dependencies:
|
# Replaces discontinued smooth_star_rating (no null-safe release).
|
||||||
# flutter_test:
|
flutter_rating_bar: ^4.0.1
|
||||||
# sdk: flutter
|
|
||||||
|
|
||||||
#dependency_overrides:
|
# Discontinued but ship a null-safe release — KEPT for now to reach a runnable
|
||||||
# webview_flutter: ^3.0.4
|
# build with minimal churn. Scheduled for proper replacement in Phase 5:
|
||||||
# path: ^1.8.0
|
# pull_to_refresh -> smart_refresher
|
||||||
|
# hive / hive_flutter -> hive_ce / hive_ce_flutter
|
||||||
|
# catcher -> catcher2
|
||||||
|
pull_to_refresh: ^2.0.0
|
||||||
|
hive: ^2.2.3
|
||||||
|
hive_flutter: ^1.1.0
|
||||||
|
catcher: ^0.8.0
|
||||||
|
|
||||||
|
# Removed in Phase 2 (no null-safe release and/or zero references):
|
||||||
|
# splashscreen, flappy_search_bar, searchable_dropdown, share, platform_detect,
|
||||||
|
# flutter_inappwebview, countdown, gender_selection, flutter_dash,
|
||||||
|
# smooth_star_rating, hovering, ffi
|
||||||
|
# Stripe payment deps removed in Phase 1 (switched to e-Transfer).
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
flutter_launcher_icons: ^0.14.1
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
@@ -112,38 +100,12 @@ flutter:
|
|||||||
- assets/
|
- assets/
|
||||||
- assets/images/
|
- assets/images/
|
||||||
- assets/tessdata/
|
- assets/tessdata/
|
||||||
# - images/a_dot_burr.jpeg
|
|
||||||
# - images/a_dot_ham.jpeg
|
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
|
||||||
# https://flutter.dev/assets-and-images/#resolution-aware.
|
|
||||||
|
|
||||||
# For details regarding adding assets from package dependencies, see
|
|
||||||
# https://flutter.dev/assets-and-images/#from-packages
|
|
||||||
|
|
||||||
# To add custom fonts to your application, add a fonts section here,
|
|
||||||
# in this "flutter" section. Each entry in this list should have a
|
|
||||||
# "family" key with the font family name, and a "fonts" key with a
|
|
||||||
# list giving the asset and other descriptors for the font. For
|
|
||||||
# example:
|
|
||||||
fonts:
|
fonts:
|
||||||
- family: wisetronic
|
- family: wisetronic
|
||||||
fonts:
|
fonts:
|
||||||
- asset: fonts/wisetronic.ttf
|
- asset: fonts/wisetronic.ttf
|
||||||
# fonts:
|
|
||||||
# - family: Schyler
|
|
||||||
# fonts:
|
|
||||||
# - asset: fonts/Schyler-Regular.ttf
|
|
||||||
# - asset: fonts/Schyler-Italic.ttf
|
|
||||||
# style: italic
|
|
||||||
# - family: Trajan Pro
|
|
||||||
# fonts:
|
|
||||||
# - asset: fonts/TrajanPro.ttf
|
|
||||||
# - asset: fonts/TrajanPro_Bold.ttf
|
|
||||||
# weight: 700
|
|
||||||
#
|
|
||||||
# For details regarding fonts from package dependencies,
|
|
||||||
# see https://flutter.dev/custom-fonts/#from-packages
|
|
||||||
flutter_intl:
|
flutter_intl:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,17 @@
|
|||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <catcher/catcher_plugin.h>
|
#include <catcher/catcher_plugin.h>
|
||||||
#include <url_launcher_windows/url_launcher_plugin.h>
|
#include <file_selector_windows/file_selector_windows.h>
|
||||||
|
#include <geolocator_windows/geolocator_windows.h>
|
||||||
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
CatcherPluginRegisterWithRegistrar(
|
CatcherPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("CatcherPlugin"));
|
registry->GetRegistrarForPlugin("CatcherPlugin"));
|
||||||
UrlLauncherPluginRegisterWithRegistrar(
|
FileSelectorWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("UrlLauncherPlugin"));
|
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||||
|
GeolocatorWindowsRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("GeolocatorWindows"));
|
||||||
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
catcher
|
catcher
|
||||||
|
file_selector_windows
|
||||||
|
geolocator_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user