chore: 添加 iOS/Android 相机和相册权限配置
This commit is contained in:
@@ -1,6 +1,11 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
|
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||||
|
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
|
|||||||
@@ -45,5 +45,9 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>NSCameraUsageDescription</key>
|
||||||
|
<string>需要使用相机来拍摄照片</string>
|
||||||
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
|
<string>需要访问相册来选择照片</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ class _CalendarDayWeekScreenState extends State<CalendarDayWeekScreen>
|
|||||||
final ScrollController _dayStripController = ScrollController();
|
final ScrollController _dayStripController = ScrollController();
|
||||||
Key _eventsKey = UniqueKey();
|
Key _eventsKey = UniqueKey();
|
||||||
List<ScheduleItemModel> _events = const [];
|
List<ScheduleItemModel> _events = const [];
|
||||||
String? _lastRoute;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -62,21 +61,18 @@ class _CalendarDayWeekScreenState extends State<CalendarDayWeekScreen>
|
|||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_scrollToSelectedDate();
|
_scrollToSelectedDate();
|
||||||
_lastRoute = GoRouterState.of(context).uri.toString();
|
_setupRouteListener();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
void _setupRouteListener() {
|
||||||
void didChangeDependencies() {
|
final router = GoRouter.of(context);
|
||||||
super.didChangeDependencies();
|
router.routerDelegate.addListener(_onRouteChange);
|
||||||
final currentRoute = GoRouterState.of(context).uri.toString();
|
}
|
||||||
if (_lastRoute != null && _lastRoute != currentRoute) {
|
|
||||||
if (!currentRoute.contains('/events/')) {
|
void _onRouteChange() {
|
||||||
_loadEvents();
|
_loadEvents();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_lastRoute = currentRoute;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateMonthDates() {
|
void _updateMonthDates() {
|
||||||
_monthDates = monthDatesFor(_selectedDate);
|
_monthDates = monthDatesFor(_selectedDate);
|
||||||
@@ -94,6 +90,9 @@ class _CalendarDayWeekScreenState extends State<CalendarDayWeekScreen>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
try {
|
||||||
|
GoRouter.of(context).routerDelegate.removeListener(_onRouteChange);
|
||||||
|
} catch (_) {}
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
_dayStripController.dispose();
|
_dayStripController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ class _CalendarMonthScreenState extends State<CalendarMonthScreen>
|
|||||||
late DateTime _selectedDate;
|
late DateTime _selectedDate;
|
||||||
Key _eventsKey = UniqueKey();
|
Key _eventsKey = UniqueKey();
|
||||||
final Map<String, List<ScheduleItemModel>> _eventsByDay = {};
|
final Map<String, List<ScheduleItemModel>> _eventsByDay = {};
|
||||||
String? _lastRoute;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -45,21 +44,18 @@ class _CalendarMonthScreenState extends State<CalendarMonthScreen>
|
|||||||
_loadMonthEvents();
|
_loadMonthEvents();
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_lastRoute = GoRouterState.of(context).uri.toString();
|
_setupRouteListener();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
void _setupRouteListener() {
|
||||||
void didChangeDependencies() {
|
final router = GoRouter.of(context);
|
||||||
super.didChangeDependencies();
|
router.routerDelegate.addListener(_onRouteChange);
|
||||||
final currentRoute = GoRouterState.of(context).uri.toString();
|
}
|
||||||
if (_lastRoute != null && _lastRoute != currentRoute) {
|
|
||||||
if (!currentRoute.contains('/events/')) {
|
void _onRouteChange() {
|
||||||
_loadMonthEvents();
|
_loadMonthEvents();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_lastRoute = currentRoute;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _loadMonthEvents() async {
|
Future<void> _loadMonthEvents() async {
|
||||||
final start = DateTime(_currentMonth.year, _currentMonth.month, 1);
|
final start = DateTime(_currentMonth.year, _currentMonth.month, 1);
|
||||||
@@ -85,6 +81,9 @@ class _CalendarMonthScreenState extends State<CalendarMonthScreen>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
try {
|
||||||
|
GoRouter.of(context).routerDelegate.removeListener(_onRouteChange);
|
||||||
|
} catch (_) {}
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,8 +113,13 @@ class _CreateEventSheetState extends State<CreateEventSheet>
|
|||||||
}
|
}
|
||||||
|
|
||||||
DateTime _roundToNearestMinute(DateTime dt, int interval) {
|
DateTime _roundToNearestMinute(DateTime dt, int interval) {
|
||||||
final minute = (dt.minute / interval).round() * interval;
|
final totalMinutes = dt.hour * 60 + dt.minute;
|
||||||
return DateTime(dt.year, dt.month, dt.day, dt.hour, minute % 60);
|
final rounded = ((totalMinutes / interval).round() * interval);
|
||||||
|
final hours = rounded ~/ 60;
|
||||||
|
final minutes = rounded % 60;
|
||||||
|
final dayOffset = hours >= 24 ? 1 : 0;
|
||||||
|
final newHour = hours % 24;
|
||||||
|
return DateTime(dt.year, dt.month, dt.day + dayOffset, newHour, minutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -242,8 +247,27 @@ class _CreateEventSheetState extends State<CreateEventSheet>
|
|||||||
_endTime ?? _startTime,
|
_endTime ?? _startTime,
|
||||||
(date, time) {
|
(date, time) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
final startDateTime = DateTime(
|
||||||
|
_startDate.year,
|
||||||
|
_startDate.month,
|
||||||
|
_startDate.day,
|
||||||
|
_startTime.hour,
|
||||||
|
_startTime.minute,
|
||||||
|
);
|
||||||
|
final endDateTime = DateTime(
|
||||||
|
date.year,
|
||||||
|
date.month,
|
||||||
|
date.day,
|
||||||
|
time.hour,
|
||||||
|
time.minute,
|
||||||
|
);
|
||||||
|
if (endDateTime.isBefore(startDateTime)) {
|
||||||
|
_endDate = _startDate;
|
||||||
|
_endTime = _startTime;
|
||||||
|
} else {
|
||||||
_endDate = date;
|
_endDate = date;
|
||||||
_endTime = time;
|
_endTime = time;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
isOptional: true,
|
isOptional: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user