优化
This commit is contained in:
@@ -1,16 +1,46 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:flutter_template/app/config/app_config.dart';
|
||||
import 'package:flutter_template/app/router/app_navigator.dart';
|
||||
import 'package:flutter_template/app/theme/app_theme.dart';
|
||||
import 'package:flutter_template/features/recording/recording_page.dart';
|
||||
import 'package:recording_tool/app/config/app_config.dart';
|
||||
import 'package:recording_tool/app/router/app_navigator.dart';
|
||||
import 'package:recording_tool/app/theme/app_theme.dart';
|
||||
import 'package:recording_tool/features/recording/recording_page.dart';
|
||||
import 'package:recording_tool/features/recording/view-model/view_model_recording.dart';
|
||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
|
||||
class FlutterTemplateApp extends StatelessWidget {
|
||||
class FlutterTemplateApp extends ConsumerStatefulWidget {
|
||||
const FlutterTemplateApp({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<FlutterTemplateApp> createState() => _FlutterTemplateAppState();
|
||||
}
|
||||
|
||||
class _FlutterTemplateAppState extends ConsumerState<FlutterTemplateApp>
|
||||
with WidgetsBindingObserver {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(recordingViewModelProvider.notifier).getClipboardContent();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
ref.read(recordingViewModelProvider.notifier).getClipboardContent();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ScreenUtilInit(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_template/app/app.dart';
|
||||
import 'package:flutter_template/app/config/app_config.dart';
|
||||
import 'package:flutter_template/core/cache/app_storage.dart';
|
||||
import 'package:flutter_template/core/logging/app_logger.dart';
|
||||
import 'package:recording_tool/app/app.dart';
|
||||
import 'package:recording_tool/app/config/app_config.dart';
|
||||
import 'package:recording_tool/core/cache/app_storage.dart';
|
||||
import 'package:recording_tool/core/logging/app_logger.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
class AppBootstrapper {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_template/core/network/api_exception.dart';
|
||||
import 'package:flutter_template/core/network/api_response.dart';
|
||||
import 'package:flutter_template/core/network/http_method.dart';
|
||||
import 'package:recording_tool/core/network/api_exception.dart';
|
||||
import 'package:recording_tool/core/network/api_response.dart';
|
||||
import 'package:recording_tool/core/network/http_method.dart';
|
||||
|
||||
typedef JsonParser<T> = T Function(dynamic json);
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_template/app/config/app_config.dart';
|
||||
import 'package:flutter_template/core/cache/app_storage.dart';
|
||||
import 'package:flutter_template/core/cache/storage_keys.dart';
|
||||
import 'package:flutter_template/core/utils/device_utils.dart';
|
||||
import 'package:recording_tool/app/config/app_config.dart';
|
||||
import 'package:recording_tool/core/cache/app_storage.dart';
|
||||
import 'package:recording_tool/core/cache/storage_keys.dart';
|
||||
import 'package:recording_tool/core/utils/device_utils.dart';
|
||||
|
||||
class HeaderInterceptor extends Interceptor {
|
||||
@override
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'dart:async';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_template/core/network/network_state.dart';
|
||||
import 'package:recording_tool/core/network/network_state.dart';
|
||||
|
||||
class NetworkMonitor {
|
||||
final _controller = StreamController<NetworkState>.broadcast();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_template/core/network/network_monitor.dart';
|
||||
import 'package:flutter_template/core/network/offline_queue/offline_queue_manager.dart';
|
||||
import 'package:flutter_template/core/network/offline_queue/offline_request.dart';
|
||||
import 'package:recording_tool/core/network/network_monitor.dart';
|
||||
import 'package:recording_tool/core/network/offline_queue/offline_queue_manager.dart';
|
||||
import 'package:recording_tool/core/network/offline_queue/offline_request.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class OfflineQueueInterceptor extends Interceptor {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_template/core/logging/app_logger.dart';
|
||||
import 'package:flutter_template/core/network/network_monitor.dart';
|
||||
import 'package:flutter_template/core/network/offline_queue/offline_queue_state.dart';
|
||||
import 'package:flutter_template/core/network/offline_queue/offline_queue_storage.dart';
|
||||
import 'package:flutter_template/core/network/offline_queue/offline_request.dart';
|
||||
import 'package:recording_tool/core/logging/app_logger.dart';
|
||||
import 'package:recording_tool/core/network/network_monitor.dart';
|
||||
import 'package:recording_tool/core/network/offline_queue/offline_queue_state.dart';
|
||||
import 'package:recording_tool/core/network/offline_queue/offline_queue_storage.dart';
|
||||
import 'package:recording_tool/core/network/offline_queue/offline_request.dart';
|
||||
|
||||
class OfflineQueueManager {
|
||||
OfflineQueueManager({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter_template/core/cache/app_storage.dart';
|
||||
import 'package:flutter_template/core/cache/storage_keys.dart';
|
||||
import 'package:flutter_template/core/network/offline_queue/offline_request.dart';
|
||||
import 'package:recording_tool/core/cache/app_storage.dart';
|
||||
import 'package:recording_tool/core/cache/storage_keys.dart';
|
||||
import 'package:recording_tool/core/network/offline_queue/offline_request.dart';
|
||||
|
||||
class OfflineQueueStorage {
|
||||
Future<List<OfflineRequest>> loadQueue() async {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_template/app/config/app_config.dart';
|
||||
import 'package:flutter_template/core/network/api_client.dart';
|
||||
import 'package:flutter_template/core/network/header_interceptor.dart';
|
||||
import 'package:flutter_template/core/network/offline_queue/offline_queue_interceptor.dart';
|
||||
import 'package:flutter_template/core/network/providers/network_providers.dart';
|
||||
import 'package:flutter_template/core/network/providers/offline_queue_providers.dart';
|
||||
import 'package:recording_tool/app/config/app_config.dart';
|
||||
import 'package:recording_tool/core/network/api_client.dart';
|
||||
import 'package:recording_tool/core/network/header_interceptor.dart';
|
||||
import 'package:recording_tool/core/network/offline_queue/offline_queue_interceptor.dart';
|
||||
import 'package:recording_tool/core/network/providers/network_providers.dart';
|
||||
import 'package:recording_tool/core/network/providers/offline_queue_providers.dart';
|
||||
|
||||
final dioProvider = Provider<Dio>((ref) {
|
||||
final dio = Dio(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_template/core/network/network_monitor.dart';
|
||||
import 'package:flutter_template/core/network/network_state.dart';
|
||||
import 'package:recording_tool/core/network/network_monitor.dart';
|
||||
import 'package:recording_tool/core/network/network_state.dart';
|
||||
|
||||
final networkMonitorProvider = Provider<NetworkMonitor>((ref) {
|
||||
final monitor = NetworkMonitor()..start();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_template/core/network/offline_queue/offline_queue_manager.dart';
|
||||
import 'package:flutter_template/core/network/offline_queue/offline_queue_state.dart';
|
||||
import 'package:flutter_template/core/network/offline_queue/offline_queue_storage.dart';
|
||||
import 'package:flutter_template/core/network/providers/network_providers.dart';
|
||||
import 'package:recording_tool/core/network/offline_queue/offline_queue_manager.dart';
|
||||
import 'package:recording_tool/core/network/offline_queue/offline_queue_state.dart';
|
||||
import 'package:recording_tool/core/network/offline_queue/offline_queue_storage.dart';
|
||||
import 'package:recording_tool/core/network/providers/network_providers.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
final offlineQueueStorageProvider = Provider<OfflineQueueStorage>((ref) {
|
||||
|
||||
44
lib/features/recording/model/model_clipboard.dart
Normal file
44
lib/features/recording/model/model_clipboard.dart
Normal file
@@ -0,0 +1,44 @@
|
||||
/// 剪切板内容数据模型
|
||||
class ClipboardRecordingModel {
|
||||
final String title;
|
||||
final int startTimestamp;
|
||||
final int endTimestamp;
|
||||
final String address;
|
||||
|
||||
ClipboardRecordingModel({
|
||||
required this.title,
|
||||
required this.startTimestamp,
|
||||
required this.endTimestamp,
|
||||
required this.address,
|
||||
});
|
||||
|
||||
factory ClipboardRecordingModel.fromJson(Map<String, dynamic> json) {
|
||||
return ClipboardRecordingModel(
|
||||
title: _readString(json, 'title'),
|
||||
startTimestamp: _readInt(json, 'startTimestamp'),
|
||||
endTimestamp: _readInt(json, 'endTimestamp'),
|
||||
address: _readString(json, 'address'),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'title': title,
|
||||
'startTimestamp': startTimestamp,
|
||||
'endTimestamp': endTimestamp,
|
||||
'address': address,
|
||||
};
|
||||
}
|
||||
|
||||
static String _readString(Map<String, dynamic> json, String key) {
|
||||
final value = json[key];
|
||||
if (value is String) return value;
|
||||
throw FormatException('Clipboard field "$key" must be a String.');
|
||||
}
|
||||
|
||||
static int _readInt(Map<String, dynamic> json, String key) {
|
||||
final value = json[key];
|
||||
if (value is int) return value;
|
||||
throw FormatException('Clipboard field "$key" must be an int.');
|
||||
}
|
||||
}
|
||||
26
lib/features/recording/model/model_recording.dart
Normal file
26
lib/features/recording/model/model_recording.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'package:recording_tool/features/recording/model/model_clipboard.dart';
|
||||
|
||||
class RecordingModel {
|
||||
/// 剪切板内容
|
||||
final ClipboardRecordingModel clipboardRecordingModel;
|
||||
|
||||
RecordingModel({required this.clipboardRecordingModel});
|
||||
|
||||
factory RecordingModel.fromJson(Map<String, dynamic> json) {
|
||||
return RecordingModel(
|
||||
clipboardRecordingModel: ClipboardRecordingModel.fromJson(
|
||||
json['clipboardRecordingModel'],
|
||||
),
|
||||
);
|
||||
}
|
||||
Map<String, dynamic> toJson() {
|
||||
return {'clipboardRecordingModel': clipboardRecordingModel.toJson()};
|
||||
}
|
||||
|
||||
RecordingModel copyWith({ClipboardRecordingModel? clipboardRecordingModel}) {
|
||||
return RecordingModel(
|
||||
clipboardRecordingModel:
|
||||
clipboardRecordingModel ?? this.clipboardRecordingModel,
|
||||
);
|
||||
}
|
||||
}
|
||||
5
lib/features/recording/recording_channel_names.dart
Normal file
5
lib/features/recording/recording_channel_names.dart
Normal file
@@ -0,0 +1,5 @@
|
||||
abstract final class RecordingChannelNames {
|
||||
static const packageName = 'com.gdfw.fxjk';
|
||||
static const method = '$packageName/recording';
|
||||
static const events = '$packageName/recording_events';
|
||||
}
|
||||
@@ -3,11 +3,12 @@ import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_template/features/recording/recording_platform.dart';
|
||||
import 'package:flutter_template/features/recording/recording_session_controller.dart';
|
||||
import 'package:flutter_template/features/recording/widgets/camera_preview_widget.dart';
|
||||
import 'package:flutter_template/features/recording/widgets/recording_touch_lock_overlay.dart';
|
||||
import 'package:flutter_template/shared/widgets/widgets.dart';
|
||||
import 'package:recording_tool/features/recording/recording_platform.dart';
|
||||
import 'package:recording_tool/features/recording/recording_session_controller.dart';
|
||||
import 'package:recording_tool/features/recording/view-model/view_model_recording.dart';
|
||||
import 'package:recording_tool/features/recording/widgets/camera_preview_widget.dart';
|
||||
import 'package:recording_tool/features/recording/widgets/recording_touch_lock_overlay.dart';
|
||||
import 'package:recording_tool/shared/widgets/widgets.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
class RecordingPage extends ConsumerStatefulWidget {
|
||||
@@ -27,6 +28,7 @@ class _RecordingPageState extends ConsumerState<RecordingPage> {
|
||||
}
|
||||
|
||||
Future<void> _bootstrap() async {
|
||||
await ref.read(recordingViewModelProvider.notifier).getClipboardContent();
|
||||
await _enterRecordingMode();
|
||||
// Allow PlatformView to attach before binding CameraX preview.
|
||||
await Future<void>.delayed(const Duration(milliseconds: 400));
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:recording_tool/features/recording/recording_channel_names.dart';
|
||||
|
||||
enum RecordingState {
|
||||
idle,
|
||||
@@ -47,10 +48,10 @@ class RecordingPlatform {
|
||||
RecordingPlatform._();
|
||||
|
||||
static const MethodChannel _channel = MethodChannel(
|
||||
'com.example.flutter_template/recording',
|
||||
RecordingChannelNames.method,
|
||||
);
|
||||
static const EventChannel _events = EventChannel(
|
||||
'com.example.flutter_template/recording_events',
|
||||
RecordingChannelNames.events,
|
||||
);
|
||||
|
||||
static bool get isSupported =>
|
||||
|
||||
@@ -3,8 +3,8 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_template/core/permission/permission_service.dart';
|
||||
import 'package:flutter_template/features/recording/recording_platform.dart';
|
||||
import 'package:recording_tool/core/permission/permission_service.dart';
|
||||
import 'package:recording_tool/features/recording/recording_platform.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
class RecordingSessionState {
|
||||
@@ -74,8 +74,8 @@ class RecordingSessionState {
|
||||
|
||||
final recordingSessionControllerProvider =
|
||||
NotifierProvider<RecordingSessionController, RecordingSessionState>(
|
||||
RecordingSessionController.new,
|
||||
);
|
||||
RecordingSessionController.new,
|
||||
);
|
||||
|
||||
class RecordingSessionController extends Notifier<RecordingSessionState> {
|
||||
StreamSubscription<RecordingStatus>? _statusSubscription;
|
||||
@@ -161,9 +161,7 @@ class RecordingSessionController extends Notifier<RecordingSessionState> {
|
||||
if (!shouldRetry) {
|
||||
rethrow;
|
||||
}
|
||||
await Future<void>.delayed(
|
||||
Duration(milliseconds: 150 * (attempt + 1)),
|
||||
);
|
||||
await Future<void>.delayed(Duration(milliseconds: 150 * (attempt + 1)));
|
||||
}
|
||||
}
|
||||
throw StateError('initializePreview retry exhausted');
|
||||
|
||||
56
lib/features/recording/view-model/view_model_recording.dart
Normal file
56
lib/features/recording/view-model/view_model_recording.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_riverpod/legacy.dart';
|
||||
import 'package:recording_tool/core/logging/app_logger.dart';
|
||||
import 'package:recording_tool/features/recording/model/model_clipboard.dart';
|
||||
import 'package:recording_tool/features/recording/model/model_recording.dart';
|
||||
|
||||
final recordingViewModelProvider =
|
||||
StateNotifierProvider<RecordingViewModel, RecordingModel>((ref) {
|
||||
return RecordingViewModel(ref);
|
||||
});
|
||||
|
||||
class RecordingViewModel extends StateNotifier<RecordingModel> {
|
||||
RecordingViewModel(this.ref)
|
||||
: super(
|
||||
RecordingModel(
|
||||
clipboardRecordingModel: ClipboardRecordingModel(
|
||||
title: '',
|
||||
startTimestamp: 0,
|
||||
endTimestamp: 0,
|
||||
address: '',
|
||||
),
|
||||
),
|
||||
);
|
||||
final Ref ref;
|
||||
|
||||
/// 从剪切板获取内容
|
||||
Future<void> getClipboardContent() async {
|
||||
try {
|
||||
final clipboardData = await Clipboard.getData(Clipboard.kTextPlain);
|
||||
final text = clipboardData?.text;
|
||||
AppLogger.debug('读取剪切板内容:$text');
|
||||
|
||||
if (text == null || text.trim().isEmpty) {
|
||||
AppLogger.info('剪切板内容为空,跳过录制信息解析');
|
||||
return;
|
||||
}
|
||||
|
||||
final decoded = jsonDecode(text);
|
||||
if (decoded is! Map<String, dynamic>) {
|
||||
AppLogger.warning('剪切板内容不是 JSON 对象,跳过录制信息解析');
|
||||
return;
|
||||
}
|
||||
|
||||
final clipboardRecordingModel = ClipboardRecordingModel.fromJson(decoded);
|
||||
state = state.copyWith(clipboardRecordingModel: clipboardRecordingModel);
|
||||
AppLogger.info('剪切板录制信息解析成功:${clipboardRecordingModel.toJson()}');
|
||||
} on FormatException catch (error) {
|
||||
AppLogger.warning('剪切板录制信息格式错误:$error');
|
||||
} catch (error, stackTrace) {
|
||||
AppLogger.debug('读取剪切板录制信息失败', error: error, stackTrace: stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>复制赛事录制码</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<button onclick="copyEventInfo()">复制赛事录制码</button>
|
||||
|
||||
<textarea id="copyText" style="position: fixed; left: -9999px;"></textarea>
|
||||
|
||||
<script>
|
||||
function copyEventInfo() {
|
||||
const data = {
|
||||
title: '王东方 丨李想 空中格斗赛',
|
||||
startTimestamp: 1717334400,
|
||||
endTimestamp: 1717334400,
|
||||
address: '广州市番禺区·粤港澳大湾区青年人才双创小镇',
|
||||
}
|
||||
|
||||
const jsonStr = JSON.stringify(data)
|
||||
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
navigator.clipboard.writeText(jsonStr)
|
||||
.then(() => {
|
||||
alert('赛事录制码已复制')
|
||||
})
|
||||
.catch(() => {
|
||||
fallbackCopy(jsonStr)
|
||||
})
|
||||
} else {
|
||||
fallbackCopy(jsonStr)
|
||||
}
|
||||
}
|
||||
|
||||
function fallbackCopy(text) {
|
||||
const textarea = document.getElementById('copyText')
|
||||
textarea.value = text
|
||||
textarea.select()
|
||||
textarea.setSelectionRange(0, textarea.value.length)
|
||||
|
||||
try {
|
||||
document.execCommand('copy')
|
||||
alert('赛事录制码已复制')
|
||||
} catch (err) {
|
||||
console.error('复制失败:', err)
|
||||
alert('复制失败,请手动复制')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,3 +1,3 @@
|
||||
import 'package:flutter_template/app/bootstrap.dart';
|
||||
import 'package:recording_tool/app/bootstrap.dart';
|
||||
|
||||
Future<void> main() => AppBootstrapper.bootstrap();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_template/shared/widgets/app_network_image.dart';
|
||||
import 'package:recording_tool/shared/widgets/app_network_image.dart';
|
||||
|
||||
class AppAvatar extends StatelessWidget {
|
||||
const AppAvatar({super.key, this.imageUrl, this.initials, this.size = 40});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_template/app/theme/app_theme.dart';
|
||||
import 'package:recording_tool/app/theme/app_theme.dart';
|
||||
|
||||
class AppCard extends StatelessWidget {
|
||||
const AppCard({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_template/shared/widgets/app_button.dart';
|
||||
import 'package:recording_tool/shared/widgets/app_button.dart';
|
||||
|
||||
class AppErrorView extends StatelessWidget {
|
||||
const AppErrorView({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_template/core/utils/rate_limiter.dart';
|
||||
import 'package:recording_tool/core/utils/rate_limiter.dart';
|
||||
|
||||
class AppSearchBar extends StatefulWidget {
|
||||
const AppSearchBar({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_template/shared/widgets/app_empty_view.dart';
|
||||
import 'package:flutter_template/shared/widgets/app_error_view.dart';
|
||||
import 'package:flutter_template/shared/widgets/app_loading_view.dart';
|
||||
import 'package:recording_tool/shared/widgets/app_empty_view.dart';
|
||||
import 'package:recording_tool/shared/widgets/app_error_view.dart';
|
||||
import 'package:recording_tool/shared/widgets/app_loading_view.dart';
|
||||
|
||||
enum AppViewStatus { loading, empty, error, content }
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_template/app/router/app_navigator.dart';
|
||||
import 'package:recording_tool/app/router/app_navigator.dart';
|
||||
|
||||
class AppToast {
|
||||
AppToast._();
|
||||
|
||||
Reference in New Issue
Block a user