24-02-1403 / Rhmn / changes: Customize category Create.
This commit is contained in:
parent
08d5564422
commit
48ccf55040
|
|
@ -33,6 +33,9 @@ class Assets {
|
||||||
static String get stockStatCat =>
|
static String get stockStatCat =>
|
||||||
'$_baseFeaturesPath/stock-$_themeSuffix.svg';
|
'$_baseFeaturesPath/stock-$_themeSuffix.svg';
|
||||||
|
|
||||||
|
static String get note =>
|
||||||
|
'$_baseFeaturesPath/note.svg';
|
||||||
|
|
||||||
static String get verticalLogoWithText =>
|
static String get verticalLogoWithText =>
|
||||||
'$_baseLogosPath/logo-vertical-$_themeSuffix.svg';
|
'$_baseLogosPath/logo-vertical-$_themeSuffix.svg';
|
||||||
static String get horizontalLogoWithText =>
|
static String get horizontalLogoWithText =>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
|
||||||
|
class FavoritesResponse {
|
||||||
|
int? id;
|
||||||
|
String? name;
|
||||||
|
bool? selected;
|
||||||
|
|
||||||
|
FavoritesResponse({this.id, this.name, this.selected});
|
||||||
|
|
||||||
|
FavoritesResponse.fromJson(Map<String, dynamic> json) {
|
||||||
|
id = json['id'];
|
||||||
|
name = json['name'];
|
||||||
|
selected = json['selected'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['id'] = this.id;
|
||||||
|
data['name'] = this.name;
|
||||||
|
data['selected'] = this.selected;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
class DayTime{
|
||||||
|
String hour;
|
||||||
|
String minute;
|
||||||
|
Meridiem meridiem;
|
||||||
|
|
||||||
|
DayTime({this.hour = "1", this.minute = "0", this.meridiem = Meridiem.AM});
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SelectorType { meridiem, hour, minute }
|
||||||
|
|
||||||
|
enum Meridiem { AM, PM }
|
||||||
|
|
@ -2,6 +2,8 @@ import 'package:didvan/views/authentication/authentication.dart';
|
||||||
import 'package:didvan/views/authentication/authentication_state.dart';
|
import 'package:didvan/views/authentication/authentication_state.dart';
|
||||||
import 'package:didvan/views/comments/comments.dart';
|
import 'package:didvan/views/comments/comments.dart';
|
||||||
import 'package:didvan/views/comments/comments_state.dart';
|
import 'package:didvan/views/comments/comments_state.dart';
|
||||||
|
import 'package:didvan/views/customize_category/customize_category_state.dart';
|
||||||
|
import 'package:didvan/views/customize_category/favorites_step.dart';
|
||||||
import 'package:didvan/views/direct/direct.dart';
|
import 'package:didvan/views/direct/direct.dart';
|
||||||
import 'package:didvan/views/direct/direct_state.dart';
|
import 'package:didvan/views/direct/direct_state.dart';
|
||||||
import 'package:didvan/views/hashtag/hashtag.dart';
|
import 'package:didvan/views/hashtag/hashtag.dart';
|
||||||
|
|
@ -20,6 +22,7 @@ import 'package:didvan/views/news/news.dart';
|
||||||
import 'package:didvan/views/news/news_details/news_details.dart';
|
import 'package:didvan/views/news/news_details/news_details.dart';
|
||||||
import 'package:didvan/views/news/news_details/news_details_state.dart';
|
import 'package:didvan/views/news/news_details/news_details_state.dart';
|
||||||
import 'package:didvan/views/news/news_state.dart';
|
import 'package:didvan/views/news/news_state.dart';
|
||||||
|
import 'package:didvan/views/notification_time/notification_time_state.dart';
|
||||||
import 'package:didvan/views/podcasts/podcasts.dart';
|
import 'package:didvan/views/podcasts/podcasts.dart';
|
||||||
import 'package:didvan/views/profile/profile.dart';
|
import 'package:didvan/views/profile/profile.dart';
|
||||||
import 'package:didvan/views/radar/radar.dart';
|
import 'package:didvan/views/radar/radar.dart';
|
||||||
|
|
@ -47,6 +50,9 @@ import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../views/customize_category/notification_status_step.dart';
|
||||||
|
import '../views/notification_time/notification_time.dart';
|
||||||
|
|
||||||
class RouteGenerator {
|
class RouteGenerator {
|
||||||
static Route<dynamic> generateRoute(RouteSettings settings) {
|
static Route<dynamic> generateRoute(RouteSettings settings) {
|
||||||
switch (settings.name) {
|
switch (settings.name) {
|
||||||
|
|
@ -54,6 +60,28 @@ class RouteGenerator {
|
||||||
return _createRoute(
|
return _createRoute(
|
||||||
const Splash(),
|
const Splash(),
|
||||||
);
|
);
|
||||||
|
case Routes.notificationTime:
|
||||||
|
return _createRoute(
|
||||||
|
ChangeNotifierProvider<NotificationTimeState>(
|
||||||
|
create: (context) => NotificationTimeState(),
|
||||||
|
child: NotificationTime(
|
||||||
|
pageData: settings.arguments as Map<String, dynamic>,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
case Routes.favouritesStep:
|
||||||
|
return _createRoute(
|
||||||
|
ChangeNotifierProvider<CustomizeCategoryState>(
|
||||||
|
create: (context) => CustomizeCategoryState(),
|
||||||
|
child: FavoritesStep()),
|
||||||
|
);
|
||||||
|
|
||||||
|
case Routes.notificationStatusStep:
|
||||||
|
return _createRoute(
|
||||||
|
ChangeNotifierProvider<CustomizeCategoryState>(
|
||||||
|
create: (context) => CustomizeCategoryState(),
|
||||||
|
child: NotificationStatusStep()),
|
||||||
|
);
|
||||||
case Routes.authenticaion:
|
case Routes.authenticaion:
|
||||||
return _createRoute(
|
return _createRoute(
|
||||||
ChangeNotifierProvider<AuthenticationState>(
|
ChangeNotifierProvider<AuthenticationState>(
|
||||||
|
|
@ -263,7 +291,8 @@ class RouteGenerator {
|
||||||
size: Size(
|
size: Size(
|
||||||
deviceSize.height * 9 / 16,
|
deviceSize.height * 9 / 16,
|
||||||
deviceSize.height,
|
deviceSize.height,
|
||||||
), textScaler: const TextScaler.linear(1.0),
|
),
|
||||||
|
textScaler: const TextScaler.linear(1.0),
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.background,
|
||||||
|
|
@ -273,7 +302,8 @@ class RouteGenerator {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return MediaQuery(
|
return MediaQuery(
|
||||||
data: MediaQuery.of(context).copyWith(textScaler: const TextScaler.linear(1.0)),
|
data: MediaQuery.of(context)
|
||||||
|
.copyWith(textScaler: const TextScaler.linear(1.0)),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Theme.of(context).colorScheme.surface,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
|
|
|
||||||
|
|
@ -25,4 +25,7 @@ class Routes {
|
||||||
static const String hashtag = '/hashtag';
|
static const String hashtag = '/hashtag';
|
||||||
static const String statGeneral = '/general';
|
static const String statGeneral = '/general';
|
||||||
static const String stock = '/stock';
|
static const String stock = '/stock';
|
||||||
|
static const String favouritesStep = '/favourites-step';
|
||||||
|
static const String notificationStatusStep = '/notification-status-step';
|
||||||
|
static const String notificationTime = '/notification-time';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'package:didvan/services/storage/storage.dart';
|
import 'package:didvan/services/storage/storage.dart';
|
||||||
|
|
||||||
// ignore: depend_on_referenced_packages
|
// ignore: depend_on_referenced_packages
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
// ignore: depend_on_referenced_packages
|
// ignore: depend_on_referenced_packages
|
||||||
import 'package:http_parser/http_parser.dart' as parser;
|
import 'package:http_parser/http_parser.dart' as parser;
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
@ -14,7 +16,9 @@ class RequestService {
|
||||||
dynamic data(String s) {
|
dynamic data(String s) {
|
||||||
return _body?[s] ?? const {};
|
return _body?[s] ?? const {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> get result => _body?['result'] ?? const {};
|
Map<String, dynamic> get result => _body?['result'] ?? const {};
|
||||||
|
|
||||||
Map<String, dynamic> get errors => _body?['errors'] ?? const {};
|
Map<String, dynamic> get errors => _body?['errors'] ?? const {};
|
||||||
|
|
||||||
String errorMessage =
|
String errorMessage =
|
||||||
|
|
@ -39,7 +43,11 @@ class RequestService {
|
||||||
}) {
|
}) {
|
||||||
if (body != null) _requestBody = body;
|
if (body != null) _requestBody = body;
|
||||||
if (requestHeaders != null) _headers.addAll(requestHeaders);
|
if (requestHeaders != null) _headers.addAll(requestHeaders);
|
||||||
if (useAutherization) _headers.addAll({'Authorization': 'Bearer $token'});
|
// if (useAutherization) _headers.addAll({'Authorization': 'Bearer $token'});
|
||||||
|
_headers.addAll({
|
||||||
|
'Authorization':
|
||||||
|
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NCwicm9sZUlkIjo0LCJhcHBJZCI6MCwiaWF0IjoxNzEzOTM1NzkwfQ.i-SO9tLy0M9j-_C2Wh8tdp01vtYGlDZIBFPygglHQF0'
|
||||||
|
});
|
||||||
if (body != null) _requestBody = body;
|
if (body != null) _requestBody = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,9 @@ class RequestHelper {
|
||||||
static String mark(int id, String type) => '$baseUrl/$type/$id/mark';
|
static String mark(int id, String type) => '$baseUrl/$type/$id/mark';
|
||||||
static String tracking(int id, String type) => '$baseUrl/$type/$id/tracking';
|
static String tracking(int id, String type) => '$baseUrl/$type/$id/tracking';
|
||||||
static String comments(int id, String type) => '$baseUrl/$type/$id/comments/v2';
|
static String comments(int id, String type) => '$baseUrl/$type/$id/comments/v2';
|
||||||
|
static String favourites() => '$baseUrl/user/favorites';
|
||||||
|
static String notificationStatus() => '$baseUrl/user/notification/status';
|
||||||
|
static String notificationTime() => '$baseUrl/user/notification/time';
|
||||||
static String usersMentions(String search) => '$baseUrl/comment/user?search=$search';
|
static String usersMentions(String search) => '$baseUrl/comment/user?search=$search';
|
||||||
static String feedback(int id, int commentId, String type) =>
|
static String feedback(int id, int commentId, String type) =>
|
||||||
'$baseUrl/$type/$id/comments/$commentId/feedback/v2';
|
'$baseUrl/$type/$id/comments/$commentId/feedback/v2';
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,41 @@
|
||||||
import 'package:didvan/config/design_config.dart';
|
import 'package:didvan/config/design_config.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
import 'package:persian_datetime_picker/persian_datetime_picker.dart';
|
import 'package:persian_datetime_picker/persian_datetime_picker.dart';
|
||||||
|
|
||||||
|
import '../models/day_time.dart';
|
||||||
|
|
||||||
class DateTimeUtils {
|
class DateTimeUtils {
|
||||||
|
static DayTime handleDayTime(String dayTime) {
|
||||||
|
DateFormat format = DateFormat("HH:mm");
|
||||||
|
DateTime dateTime = format.parse(dayTime);
|
||||||
|
int _selectedTimeHour = dateTime.hour;
|
||||||
|
String _selectedTimeMinute = dateTime.minute.toString();
|
||||||
|
Meridiem _selectedMeridiem = Meridiem.AM;
|
||||||
|
|
||||||
|
if (_selectedTimeHour > 12) {
|
||||||
|
_selectedTimeHour -= 12;
|
||||||
|
_selectedMeridiem = Meridiem.PM;
|
||||||
|
} else if (_selectedTimeHour == 0) {
|
||||||
|
_selectedTimeHour = 24;
|
||||||
|
_selectedMeridiem = Meridiem.AM;
|
||||||
|
}
|
||||||
|
return DayTime(
|
||||||
|
hour: _selectedTimeHour.toString(),
|
||||||
|
minute: _selectedTimeMinute,
|
||||||
|
meridiem: _selectedMeridiem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String handleDayTimeReverse(DayTime dayTime) {
|
||||||
|
String h = dayTime.hour;
|
||||||
|
String m = dayTime.minute.padLeft(2, "0");
|
||||||
|
if (dayTime.meridiem == Meridiem.PM) {
|
||||||
|
h = (int.parse(h) + 12).toString().padLeft(2, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
return "$h:$m";
|
||||||
|
}
|
||||||
|
|
||||||
static TimeOfDay stringToTimeOfDay(String input) => TimeOfDay(
|
static TimeOfDay stringToTimeOfDay(String input) => TimeOfDay(
|
||||||
hour: int.parse(input.split(':')[0]),
|
hour: int.parse(input.split(':')[0]),
|
||||||
minute: int.parse(input.split(':')[1]),
|
minute: int.parse(input.split(':')[1]),
|
||||||
|
|
@ -58,6 +91,38 @@ class DateTimeUtils {
|
||||||
return result?.toDateTime().toString();
|
return result?.toDateTime().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<String?> showCupertinoDatePicker({
|
||||||
|
String? initialDate,
|
||||||
|
String? startDate,
|
||||||
|
String? endDate,
|
||||||
|
}) async {
|
||||||
|
final initDate = initialDate == null ? null : DateTime.parse(initialDate);
|
||||||
|
final initialJalali = Jalali.fromDateTime(initDate ?? DateTime.now());
|
||||||
|
|
||||||
|
final firstDate = Jalali.fromDateTime(
|
||||||
|
startDate == null ? DateTime(2021) : DateTime.parse(startDate),
|
||||||
|
);
|
||||||
|
|
||||||
|
final lastDate = Jalali.fromDateTime(
|
||||||
|
endDate == null ? DateTime.now() : DateTime.parse(endDate),
|
||||||
|
);
|
||||||
|
|
||||||
|
final Jalali? result = await showPersianDatePicker(
|
||||||
|
context: DesignConfig.context!,
|
||||||
|
initialDate: initialJalali,
|
||||||
|
firstDate: firstDate,
|
||||||
|
lastDate: lastDate,
|
||||||
|
builder: (context, child) => Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
textTheme: Theme.of(context).textTheme.copyWith(
|
||||||
|
headlineMedium: Theme.of(context).textTheme.displaySmall)),
|
||||||
|
child: child!,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return result?.toDateTime().toString();
|
||||||
|
}
|
||||||
|
|
||||||
static String timeWithAmPm(String input) {
|
static String timeWithAmPm(String input) {
|
||||||
final dateTime = utcToLocalTime(input);
|
final dateTime = utcToLocalTime(input);
|
||||||
bool isAm = true;
|
bool isAm = true;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
import 'package:didvan/models/customize_categories/favorites_response.dart';
|
||||||
|
import 'package:didvan/models/enums.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
import '../../providers/core.dart';
|
||||||
|
import '../../routes/routes.dart';
|
||||||
|
import '../../services/network/request.dart';
|
||||||
|
import '../../services/network/request_helper.dart';
|
||||||
|
|
||||||
|
class CustomizeCategoryState extends CoreProvier {
|
||||||
|
CustomizeCategoryState() {
|
||||||
|
appState = AppState.idle;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<int> selectedFavIds = [];
|
||||||
|
List<int> selectedNotifIds = [];
|
||||||
|
final List<FavoritesResponse> faves = [];
|
||||||
|
final List<FavoritesResponse> notifs = [];
|
||||||
|
|
||||||
|
Future<void> getFavourites() async {
|
||||||
|
appState = AppState.busy;
|
||||||
|
|
||||||
|
final service = RequestService(
|
||||||
|
RequestHelper.favourites(),
|
||||||
|
);
|
||||||
|
await service.httpGet();
|
||||||
|
if (service.isSuccess) {
|
||||||
|
faves.clear();
|
||||||
|
final favourites = service.data('types');
|
||||||
|
for (var i = 0; i < favourites.length; i++) {
|
||||||
|
faves.add(FavoritesResponse.fromJson(favourites[i]));
|
||||||
|
}
|
||||||
|
selectedFavIds.clear();
|
||||||
|
faves.forEach((element) {
|
||||||
|
if (element.selected!) {
|
||||||
|
selectedFavIds.add(element.id!);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
appState = AppState.idle;
|
||||||
|
} else {
|
||||||
|
appState = AppState.failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getNotificationStatuses() async {
|
||||||
|
appState = AppState.busy;
|
||||||
|
|
||||||
|
final service = RequestService(
|
||||||
|
RequestHelper.notificationStatus(),
|
||||||
|
);
|
||||||
|
await service.httpGet();
|
||||||
|
if (service.isSuccess) {
|
||||||
|
final notificationsStatuses = service.data('types');
|
||||||
|
for (var i = 0; i < notificationsStatuses.length; i++) {
|
||||||
|
notifs.add(FavoritesResponse.fromJson(notificationsStatuses[i]));
|
||||||
|
}
|
||||||
|
selectedNotifIds.clear();
|
||||||
|
notifs.forEach((element) {
|
||||||
|
if (element.selected!) {
|
||||||
|
selectedNotifIds.add(element.id!);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
appState = AppState.idle;
|
||||||
|
} else {
|
||||||
|
appState = AppState.failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> putFavourites(BuildContext context) async {
|
||||||
|
// appState = AppState.busy;
|
||||||
|
final favoritesRequest = {"favorites": selectedFavIds};
|
||||||
|
final service = RequestService(
|
||||||
|
RequestHelper.favourites(),
|
||||||
|
body: favoritesRequest,
|
||||||
|
);
|
||||||
|
await service.put();
|
||||||
|
if (service.isSuccess) {
|
||||||
|
Navigator.of(context).pushNamed(
|
||||||
|
Routes.notificationStatusStep,
|
||||||
|
);
|
||||||
|
appState = AppState.idle;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
appState = AppState.failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> putNotificationsStatuses(BuildContext context) async {
|
||||||
|
// appState = AppState.busy;
|
||||||
|
final notificationsStatusesRequest = {"notification": selectedNotifIds};
|
||||||
|
final service = RequestService(
|
||||||
|
RequestHelper.notificationStatus(),
|
||||||
|
body: notificationsStatusesRequest,
|
||||||
|
);
|
||||||
|
await service.put();
|
||||||
|
if (service.isSuccess) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
appState = AppState.idle;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
appState = AppState.failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> changeSelected(int index, List<FavoritesResponse> list,List<int> selectedIds) async {
|
||||||
|
list[index].selected = !list[index].selected!;
|
||||||
|
selectedIds.clear();
|
||||||
|
for (var ls in list) {
|
||||||
|
if (ls.selected!) {
|
||||||
|
selectedIds.add(ls.id!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
import 'package:didvan/config/theme_data.dart';
|
||||||
|
import 'package:didvan/models/enums.dart';
|
||||||
|
import 'package:didvan/models/users_mention.dart';
|
||||||
|
import 'package:didvan/models/view/app_bar_data.dart';
|
||||||
|
import 'package:didvan/views/customize_category/customize_category_state.dart';
|
||||||
|
import 'package:didvan/views/customize_category/widgets/customize_category_checkbox.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/checkbox.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/scaffold.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../../config/design_config.dart';
|
||||||
|
import '../../constants/assets.dart';
|
||||||
|
import '../widgets/didvan/button.dart';
|
||||||
|
import '../widgets/shimmer_placeholder.dart';
|
||||||
|
import '../widgets/state_handlers/empty_state.dart';
|
||||||
|
import '../widgets/state_handlers/sliver_state_handler.dart';
|
||||||
|
import '../widgets/user_mention.dart';
|
||||||
|
|
||||||
|
class FavoritesStep extends StatefulWidget {
|
||||||
|
const FavoritesStep({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FavoritesStep> createState() => _FavoritesStepState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FavoritesStepState extends State<FavoritesStep> {
|
||||||
|
late CustomizeCategoryState state;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
state = context.read<CustomizeCategoryState>();
|
||||||
|
|
||||||
|
Future.delayed(
|
||||||
|
Duration.zero,
|
||||||
|
() => state.getFavourites(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
state = context.read<CustomizeCategoryState>();
|
||||||
|
|
||||||
|
return Material(
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
DidvanScaffold(
|
||||||
|
appBarData: AppBarData(
|
||||||
|
hasBack: true,
|
||||||
|
title: 'شخصیسازی برنامه',
|
||||||
|
),
|
||||||
|
physics: const BouncingScrollPhysics(),
|
||||||
|
hidePlayer: true,
|
||||||
|
padding: const EdgeInsets.all(16).copyWith(bottom: 92),
|
||||||
|
showSliversFirst: false,
|
||||||
|
slivers: [
|
||||||
|
Consumer<CustomizeCategoryState>(
|
||||||
|
builder: (context, state, child) =>
|
||||||
|
SliverStateHandler<CustomizeCategoryState>(
|
||||||
|
onRetry: state.getFavourites,
|
||||||
|
state: state,
|
||||||
|
itemPadding: const EdgeInsets.only(bottom: 16),
|
||||||
|
childCount: state.faves.length,
|
||||||
|
placeholder: ShimmerPlaceholder(
|
||||||
|
height: 48,
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
borderRadius: DesignConfig.mediumBorderRadius,
|
||||||
|
),
|
||||||
|
centerEmptyState: false,
|
||||||
|
enableEmptyState: false,
|
||||||
|
emptyState: EmptyState(
|
||||||
|
asset: Assets.emptyChat,
|
||||||
|
title: 'اولین نظر را بنویسید...',
|
||||||
|
),
|
||||||
|
builder: (context, state, index) => Center(
|
||||||
|
child: Container(
|
||||||
|
height: 48,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(
|
||||||
|
width: 1,
|
||||||
|
color: state.faves[index].selected!
|
||||||
|
? Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.focusedBorder
|
||||||
|
: Theme.of(context).colorScheme.cardBorder),
|
||||||
|
color: state.faves[index].selected!
|
||||||
|
? Theme.of(context).colorScheme.focused
|
||||||
|
: Theme.of(context).colorScheme.cardBorder),
|
||||||
|
child: CustomizeCategoryCheckbox(
|
||||||
|
title: state.faves[index].name!,
|
||||||
|
value: state.faves[index].selected,
|
||||||
|
color: Theme.of(context).colorScheme.title,
|
||||||
|
onChanged: (val) {
|
||||||
|
state.changeSelected(index, state.faves,state.selectedFavIds);
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
children: [
|
||||||
|
DidvanText(
|
||||||
|
"کاربر گرامی لطفا دستهبندیهای مورد علاقه خود را انتخاب کنید",
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 40,
|
||||||
|
left: 16,
|
||||||
|
right: 16,
|
||||||
|
child: DidvanButton(
|
||||||
|
onPressed: state.appState == AppState.idle
|
||||||
|
? () async {
|
||||||
|
await state.putFavourites(context);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
title: 'تایید',
|
||||||
|
style: ButtonStyleMode.primary,
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
import 'package:didvan/config/theme_data.dart';
|
||||||
|
import 'package:didvan/models/enums.dart';
|
||||||
|
import 'package:didvan/models/users_mention.dart';
|
||||||
|
import 'package:didvan/models/view/app_bar_data.dart';
|
||||||
|
import 'package:didvan/views/customize_category/customize_category_state.dart';
|
||||||
|
import 'package:didvan/views/customize_category/widgets/customize_category_checkbox.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/checkbox.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/scaffold.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/switch.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../../config/design_config.dart';
|
||||||
|
import '../../constants/assets.dart';
|
||||||
|
import '../widgets/didvan/button.dart';
|
||||||
|
import '../widgets/shimmer_placeholder.dart';
|
||||||
|
import '../widgets/state_handlers/empty_state.dart';
|
||||||
|
import '../widgets/state_handlers/sliver_state_handler.dart';
|
||||||
|
import '../widgets/user_mention.dart';
|
||||||
|
|
||||||
|
class NotificationStatusStep extends StatefulWidget {
|
||||||
|
const NotificationStatusStep({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<NotificationStatusStep> createState() => _NotificationStatusStepState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NotificationStatusStepState extends State<NotificationStatusStep> {
|
||||||
|
late CustomizeCategoryState state;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
state = context.read<CustomizeCategoryState>();
|
||||||
|
|
||||||
|
Future.delayed(
|
||||||
|
Duration.zero,
|
||||||
|
() => state.getNotificationStatuses(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
state = context.watch<CustomizeCategoryState>();
|
||||||
|
|
||||||
|
return Material(
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
DidvanScaffold(
|
||||||
|
appBarData: AppBarData(
|
||||||
|
hasBack: true,
|
||||||
|
title: 'شخصیسازی برنامه',
|
||||||
|
),
|
||||||
|
physics: const BouncingScrollPhysics(),
|
||||||
|
hidePlayer: true,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
showSliversFirst: false,
|
||||||
|
slivers: [
|
||||||
|
Consumer<CustomizeCategoryState>(
|
||||||
|
builder: (context, state, child) =>
|
||||||
|
SliverStateHandler<CustomizeCategoryState>(
|
||||||
|
onRetry: state.getNotificationStatuses,
|
||||||
|
state: state,
|
||||||
|
itemPadding: const EdgeInsets.only(bottom: 16),
|
||||||
|
childCount: state.notifs.length,
|
||||||
|
placeholder: ShimmerPlaceholder(
|
||||||
|
height: 48,
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
borderRadius: DesignConfig.mediumBorderRadius,
|
||||||
|
),
|
||||||
|
centerEmptyState: false,
|
||||||
|
enableEmptyState: false,
|
||||||
|
emptyState: EmptyState(
|
||||||
|
asset: Assets.emptyChat,
|
||||||
|
title: 'اولین نظر را بنویسید...',
|
||||||
|
),
|
||||||
|
builder: (context, state, index) => Column(
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
DidvanSwitch(
|
||||||
|
value: state.notifs[index].selected!,
|
||||||
|
title: state.notifs[index].name!,
|
||||||
|
onChanged: (val) {
|
||||||
|
state.changeSelected(index, state.notifs,state.selectedNotifIds);
|
||||||
|
}),
|
||||||
|
index != state.notifs.length - 1
|
||||||
|
? Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
bottom: 16, top: 16),
|
||||||
|
child: Divider(
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.border,
|
||||||
|
height: 1,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: index == state.notifs.length - 1 ? 92 : 0,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
children: [
|
||||||
|
DidvanText(
|
||||||
|
"همیشه با اعلانات شخصیسازی شده خود بروز بمانید",
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 40,
|
||||||
|
left: 16,
|
||||||
|
right: 16,
|
||||||
|
child: DidvanButton(
|
||||||
|
onPressed: state.appState == AppState.idle
|
||||||
|
? () async {
|
||||||
|
await state.putNotificationsStatuses(context);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
title: 'تایید',
|
||||||
|
style: ButtonStyleMode.primary,
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
import 'package:didvan/config/design_config.dart';
|
||||||
|
import 'package:didvan/config/theme_data.dart';
|
||||||
|
import 'package:didvan/views/widgets/animated_visibility.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CustomizeCategoryCheckbox extends StatefulWidget {
|
||||||
|
final String title;
|
||||||
|
final bool? value;
|
||||||
|
final double size;
|
||||||
|
final Color? color;
|
||||||
|
final void Function(bool value) onChanged;
|
||||||
|
const CustomizeCategoryCheckbox({
|
||||||
|
Key? key,
|
||||||
|
required this.title,
|
||||||
|
required this.value,
|
||||||
|
required this.onChanged, this.size = 15, this.color,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CustomizeCategoryCheckbox> createState() => _CustomizeCategoryCheckboxState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CustomizeCategoryCheckboxState extends State<CustomizeCategoryCheckbox> {
|
||||||
|
bool _value = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
if (widget.value != null) {
|
||||||
|
_value = widget.value!;
|
||||||
|
}
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Color? _color = widget.color;
|
||||||
|
_color ??= Theme.of(context).colorScheme.caption;
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_value = !_value;
|
||||||
|
});
|
||||||
|
widget.onChanged(_value);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Transform.scale(
|
||||||
|
scale: widget.size ==15 ? 1 : 0.8,
|
||||||
|
child: Container(
|
||||||
|
width: 18,
|
||||||
|
height: 18,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.circular(6),
|
||||||
|
border: Border.all(width: 1.0, color: _value? _color: Theme.of(context).colorScheme.caption),
|
||||||
|
|
||||||
|
),
|
||||||
|
margin: EdgeInsets.all(8),
|
||||||
|
child: AnimatedVisibility(
|
||||||
|
isVisible: _value,
|
||||||
|
duration: DesignConfig.mediumAnimationDuration,
|
||||||
|
child: Center(child: Icon(Icons.check,size: 12,color: _value? _color: Theme.of(context).colorScheme.caption,))
|
||||||
|
),
|
||||||
|
),
|
||||||
|
), DidvanText(widget.title,fontSize: widget.size,color: _value? _color: Theme.of(context).colorScheme.caption, ),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
import 'package:didvan/config/design_config.dart';
|
||||||
|
import 'package:didvan/config/theme_data.dart';
|
||||||
|
import 'package:didvan/views/widgets/animated_visibility.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/switch.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CustomizeCategorySwitch extends StatefulWidget {
|
||||||
|
final String title;
|
||||||
|
final bool? value;
|
||||||
|
final double size;
|
||||||
|
final Color? color;
|
||||||
|
final void Function(bool value) onChanged;
|
||||||
|
|
||||||
|
const CustomizeCategorySwitch({
|
||||||
|
Key? key,
|
||||||
|
required this.title,
|
||||||
|
required this.value,
|
||||||
|
required this.onChanged,
|
||||||
|
this.size = 15,
|
||||||
|
this.color,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CustomizeCategorySwitch> createState() =>
|
||||||
|
_CustomizeCategorySwitchState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CustomizeCategorySwitchState extends State<CustomizeCategorySwitch> {
|
||||||
|
bool _value = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
if (widget.value != null) {
|
||||||
|
_value = widget.value!;
|
||||||
|
}
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Color? _color = widget.color;
|
||||||
|
_color ??= Theme.of(context).colorScheme.caption;
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_value = !_value;
|
||||||
|
});
|
||||||
|
widget.onChanged(_value);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Transform.scale(
|
||||||
|
scale: widget.size == 15 ? 1 : 0.8,
|
||||||
|
child: DidvanSwitch(
|
||||||
|
value: _value, title: widget.title, onChanged: (val) {}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
import 'package:didvan/config/theme_data.dart';
|
||||||
|
import 'package:didvan/models/day_time.dart';
|
||||||
|
import 'package:didvan/models/enums.dart';
|
||||||
|
import 'package:didvan/models/users_mention.dart';
|
||||||
|
import 'package:didvan/models/view/app_bar_data.dart';
|
||||||
|
import 'package:didvan/views/customize_category/customize_category_state.dart';
|
||||||
|
import 'package:didvan/views/notification_time/notification_time_state.dart';
|
||||||
|
import 'package:didvan/views/notification_time/widgets/custom_cupertino_date_picker.dart';
|
||||||
|
import 'package:didvan/views/customize_category/widgets/customize_category_checkbox.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/checkbox.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/scaffold.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/switch.dart';
|
||||||
|
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:persian_datetime_picker/persian_datetime_picker.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../../constants/assets.dart';
|
||||||
|
import '../widgets/date_picker_button.dart';
|
||||||
|
import '../widgets/didvan/button.dart';
|
||||||
|
import '../widgets/state_handlers/empty_state.dart';
|
||||||
|
import '../widgets/state_handlers/sliver_state_handler.dart';
|
||||||
|
import '../widgets/user_mention.dart';
|
||||||
|
|
||||||
|
class NotificationTime extends StatefulWidget {
|
||||||
|
final Map<String, dynamic> pageData;
|
||||||
|
|
||||||
|
const NotificationTime({super.key, required this.pageData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<NotificationTime> createState() => _NotificationTimeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NotificationTimeState extends State<NotificationTime> {
|
||||||
|
late NotificationTimeState state;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
state = context.read<NotificationTimeState>();
|
||||||
|
state.onTimeChanged = widget.pageData['onTimeChanged'];
|
||||||
|
Future.delayed(
|
||||||
|
Duration.zero,
|
||||||
|
() => state.getTime(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
state = context.watch<NotificationTimeState>();
|
||||||
|
return Material(
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
DidvanScaffold(
|
||||||
|
appBarData: AppBarData(
|
||||||
|
hasBack: true,
|
||||||
|
title: 'شخصیسازی برنامه',
|
||||||
|
),
|
||||||
|
physics: const BouncingScrollPhysics(),
|
||||||
|
hidePlayer: true,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
showSliversFirst: false,
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.background,
|
||||||
|
slivers: [],
|
||||||
|
children: [
|
||||||
|
Consumer<NotificationTimeState>(
|
||||||
|
builder: (context, state, child) => Column(
|
||||||
|
children: [
|
||||||
|
DidvanText(
|
||||||
|
"لطفا زمان دریافت اعلانات خود را مشخص کنید",
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
state.appState == AppState.idle
|
||||||
|
? Container(
|
||||||
|
margin: EdgeInsets.all(24),
|
||||||
|
height: 210,
|
||||||
|
child: CustomCupertinoDatePicker(
|
||||||
|
itemExtent: 64,
|
||||||
|
selectedTime: state.selectedTime,
|
||||||
|
selectedStyle: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium!
|
||||||
|
.copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.white),
|
||||||
|
unselectedStyle:
|
||||||
|
Theme.of(context).textTheme.titleSmall,
|
||||||
|
disabledStyle: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium!
|
||||||
|
.copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.disabledText),
|
||||||
|
onSelectedItemChanged: (date) {
|
||||||
|
state.selectedTime = date;
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
: SizedBox(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 40,
|
||||||
|
left: 16,
|
||||||
|
right: 16,
|
||||||
|
child: DidvanButton(
|
||||||
|
onPressed: () {
|
||||||
|
state.putTime(context);
|
||||||
|
},
|
||||||
|
title: 'تایید',
|
||||||
|
style: ButtonStyleMode.primary,
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
import 'package:didvan/models/enums.dart';
|
||||||
|
import 'package:didvan/providers/core.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../../models/day_time.dart';
|
||||||
|
import '../../routes/routes.dart';
|
||||||
|
import '../../services/network/request.dart';
|
||||||
|
import '../../services/network/request_helper.dart';
|
||||||
|
import '../../utils/date_time.dart';
|
||||||
|
import '../profile/general_settings/settings_state.dart';
|
||||||
|
|
||||||
|
class NotificationTimeState extends CoreProvier {
|
||||||
|
late DayTime selectedTime;
|
||||||
|
|
||||||
|
late void Function( ) onTimeChanged;
|
||||||
|
|
||||||
|
Future<void> getTime() async {
|
||||||
|
appState = AppState.busy;
|
||||||
|
|
||||||
|
final service = RequestService(
|
||||||
|
RequestHelper.notificationTime(),
|
||||||
|
);
|
||||||
|
await service.httpGet();
|
||||||
|
if (service.isSuccess) {
|
||||||
|
final time = service.data('time');
|
||||||
|
selectedTime = DateTimeUtils.handleDayTime(time);
|
||||||
|
|
||||||
|
appState = AppState.idle;
|
||||||
|
} else {
|
||||||
|
appState = AppState.failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> putTime(BuildContext context) async {
|
||||||
|
appState = AppState.busy;
|
||||||
|
|
||||||
|
final favoritesRequest = {
|
||||||
|
"time": DateTimeUtils.handleDayTimeReverse(selectedTime)
|
||||||
|
};
|
||||||
|
final service = RequestService(
|
||||||
|
RequestHelper.notificationTime(),
|
||||||
|
body: favoritesRequest,
|
||||||
|
);
|
||||||
|
await service.put();
|
||||||
|
if (service.isSuccess) {
|
||||||
|
onTimeChanged();
|
||||||
|
|
||||||
|
// Navigator.of(context).pushNamed(
|
||||||
|
// Routes.notificationStatusStep,
|
||||||
|
// );
|
||||||
|
appState = AppState.idle;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
appState = AppState.failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,341 @@
|
||||||
|
import 'package:day_night_time_picker/lib/state/time.dart';
|
||||||
|
import 'package:didvan/config/theme_data.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
import '../../../models/day_time.dart';
|
||||||
|
import '../../../utils/date_time.dart';
|
||||||
|
|
||||||
|
class CustomCupertinoDatePicker extends StatefulWidget {
|
||||||
|
final double itemExtent;
|
||||||
|
final void Function(DayTime)
|
||||||
|
onSelectedItemChanged; // Text style of selected item
|
||||||
|
final TextStyle? selectedStyle; // Text style of unselected item
|
||||||
|
final TextStyle? unselectedStyle; // Text style of disabled item
|
||||||
|
final TextStyle? disabledStyle; // Minimum selectable date
|
||||||
|
final DayTime? selectedTime;
|
||||||
|
|
||||||
|
const CustomCupertinoDatePicker({
|
||||||
|
Key? key,
|
||||||
|
required this.itemExtent,
|
||||||
|
required this.onSelectedItemChanged,
|
||||||
|
this.selectedTime,
|
||||||
|
this.selectedStyle,
|
||||||
|
this.unselectedStyle,
|
||||||
|
this.disabledStyle,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CustomCupertinoDatePicker> createState() =>
|
||||||
|
_CustomCupertinoDatePickerState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CustomCupertinoDatePickerState extends State<CustomCupertinoDatePicker> {
|
||||||
|
late DayTime selectedTime = DateTimeUtils.handleDayTime(
|
||||||
|
"${DateTime.now().hour.toString()}:${DateTime.now().minute.toString()}");
|
||||||
|
|
||||||
|
late int _selectedMeridiemIndex;
|
||||||
|
late int _selectedHourIndex;
|
||||||
|
late int _selectedMinuteIndex;
|
||||||
|
|
||||||
|
late final FixedExtentScrollController _meridiemScrollController;
|
||||||
|
late final FixedExtentScrollController _hourScrollController;
|
||||||
|
late final FixedExtentScrollController _minuteScrollController;
|
||||||
|
|
||||||
|
final _meridiem = [
|
||||||
|
'قبل از ظهر',
|
||||||
|
'بعد از ظهر',
|
||||||
|
];
|
||||||
|
|
||||||
|
final _timeH = [];
|
||||||
|
|
||||||
|
final _timeM = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 1; i < 12 + 1; i++) {
|
||||||
|
String twoDigitNumber = i.toString().padLeft(2, '0');
|
||||||
|
_timeH.add(twoDigitNumber);
|
||||||
|
}
|
||||||
|
for (int i = 1; i < 12 + 1; i++) {
|
||||||
|
String twoDigitNumber = i.toString().padLeft(2, '0');
|
||||||
|
_timeH.add(twoDigitNumber);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 59 + 1; i++) {
|
||||||
|
String twoDigitNumber = i.toString().padLeft(2, '0');
|
||||||
|
_timeM.add(twoDigitNumber);
|
||||||
|
}
|
||||||
|
_meridiemScrollController = FixedExtentScrollController();
|
||||||
|
_hourScrollController = FixedExtentScrollController();
|
||||||
|
_minuteScrollController = FixedExtentScrollController();
|
||||||
|
if(widget.selectedTime !=null){
|
||||||
|
selectedTime = widget.selectedTime!;
|
||||||
|
|
||||||
|
}
|
||||||
|
_initDates();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _initDates() {
|
||||||
|
_selectedMeridiemIndex = 0;
|
||||||
|
|
||||||
|
switch(selectedTime.meridiem){
|
||||||
|
case Meridiem.AM:
|
||||||
|
_selectedMeridiemIndex = 0;
|
||||||
|
_selectedHourIndex = int.parse(selectedTime.hour)-1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Meridiem.PM:
|
||||||
|
_selectedMeridiemIndex = 1;
|
||||||
|
_selectedHourIndex = (int.parse(selectedTime.hour)+12)-1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_selectedMinuteIndex = int.parse(selectedTime.minute);
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_scrollList(_meridiemScrollController, _selectedMeridiemIndex);
|
||||||
|
_scrollList(_hourScrollController, _selectedHourIndex);
|
||||||
|
_scrollList(_minuteScrollController, _selectedMinuteIndex);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _scrollList(FixedExtentScrollController controller, int index) {
|
||||||
|
controller.animateToItem(
|
||||||
|
index,
|
||||||
|
curve: Curves.easeIn,
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_meridiemScrollController.dispose();
|
||||||
|
_hourScrollController.dispose();
|
||||||
|
_minuteScrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onSelectedItemChanged(int index, SelectorType type) {
|
||||||
|
switch (type) {
|
||||||
|
case SelectorType.meridiem:
|
||||||
|
|
||||||
|
_selectedMeridiemIndex = index; // if month is changed to february &
|
||||||
|
if (_selectedMeridiemIndex == 0) {
|
||||||
|
if (_selectedHourIndex > 12 - 1) {
|
||||||
|
_selectedHourIndex -= 12;
|
||||||
|
_hourScrollController.jumpToItem(_selectedHourIndex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_selectedHourIndex < 12 - 1) {
|
||||||
|
_selectedHourIndex += 12;
|
||||||
|
_hourScrollController.jumpToItem(_selectedHourIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(index == 0){
|
||||||
|
selectedTime.meridiem = Meridiem.AM;
|
||||||
|
}else{
|
||||||
|
selectedTime.meridiem = Meridiem.PM;
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SelectorType.hour:
|
||||||
|
|
||||||
|
_selectedHourIndex = index; // if month is changed to february &
|
||||||
|
if (_selectedHourIndex > 12 - 1) {
|
||||||
|
_selectedMeridiemIndex = 1;
|
||||||
|
_meridiemScrollController.jumpToItem(_selectedMeridiemIndex);
|
||||||
|
} else {
|
||||||
|
_selectedMeridiemIndex = 0;
|
||||||
|
_meridiemScrollController.jumpToItem(_selectedMeridiemIndex);
|
||||||
|
}
|
||||||
|
selectedTime.hour = _timeH[index];
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SelectorType.minute:
|
||||||
|
_selectedMinuteIndex = index;
|
||||||
|
selectedTime.minute = _timeM[index];
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {});
|
||||||
|
widget.onSelectedItemChanged(selectedTime!);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// check if the given day, month or year index is disabled
|
||||||
|
bool _isDisabled(int index, SelectorType type) {
|
||||||
|
switch (type) {
|
||||||
|
case SelectorType.meridiem:
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SelectorType.hour:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SelectorType.minute:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Color _shadow = Theme.of(context).colorScheme.background;
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Positioned.fill(
|
||||||
|
child: Center(
|
||||||
|
child: Container(
|
||||||
|
height: 64,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
borderRadius: BorderRadius.circular(18)),
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 12),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
SizedBox(),
|
||||||
|
VerticalDivider(
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
VerticalDivider(
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
SizedBox(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(child: _meridiemSelector()),
|
||||||
|
Expanded(child: _minuteSelector()),
|
||||||
|
Expanded(child: _hourSelector()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Container(
|
||||||
|
height: 32,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: [
|
||||||
|
_shadow.withOpacity(1),
|
||||||
|
_shadow.withOpacity(0.9),
|
||||||
|
_shadow.withOpacity(0.8),
|
||||||
|
_shadow.withOpacity(0.6),
|
||||||
|
_shadow.withOpacity(0.5),
|
||||||
|
_shadow.withOpacity(0.4),
|
||||||
|
])),
|
||||||
|
)),
|
||||||
|
Positioned(
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Container(
|
||||||
|
height: 32,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.bottomCenter,
|
||||||
|
end: Alignment.topCenter,
|
||||||
|
colors: [
|
||||||
|
_shadow.withOpacity(1),
|
||||||
|
_shadow.withOpacity(0.9),
|
||||||
|
_shadow.withOpacity(0.8),
|
||||||
|
_shadow.withOpacity(0.6),
|
||||||
|
_shadow.withOpacity(0.5),
|
||||||
|
_shadow.withOpacity(0.4),
|
||||||
|
])),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _selector({
|
||||||
|
required List<dynamic> values,
|
||||||
|
required int selectedValueIndex,
|
||||||
|
required bool Function(int) isDisabled,
|
||||||
|
required void Function(int) onSelectedItemChanged,
|
||||||
|
required FixedExtentScrollController scrollController,
|
||||||
|
}) {
|
||||||
|
return CupertinoPicker.builder(
|
||||||
|
childCount: values.length,
|
||||||
|
itemExtent: widget.itemExtent,
|
||||||
|
scrollController: scrollController,
|
||||||
|
squeeze: 1.45,
|
||||||
|
useMagnifier: false,
|
||||||
|
diameterRatio: 2.3,
|
||||||
|
magnification: 1.0,
|
||||||
|
offAxisFraction: 0.0,
|
||||||
|
selectionOverlay: const SizedBox(),
|
||||||
|
onSelectedItemChanged: onSelectedItemChanged,
|
||||||
|
itemBuilder: (context, index) => Container(
|
||||||
|
height: widget.itemExtent,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Text(
|
||||||
|
'${values[index]}',
|
||||||
|
style: index == selectedValueIndex
|
||||||
|
? widget.selectedStyle
|
||||||
|
: isDisabled(index)
|
||||||
|
? widget.disabledStyle
|
||||||
|
: widget.unselectedStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _meridiemSelector() {
|
||||||
|
return _selector(
|
||||||
|
values: _meridiem,
|
||||||
|
selectedValueIndex: _selectedMeridiemIndex,
|
||||||
|
scrollController: _meridiemScrollController,
|
||||||
|
isDisabled: (index) => _isDisabled(index, SelectorType.meridiem),
|
||||||
|
onSelectedItemChanged: (v) => _onSelectedItemChanged(
|
||||||
|
v,
|
||||||
|
SelectorType.meridiem,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _hourSelector() {
|
||||||
|
return _selector(
|
||||||
|
values: _timeH,
|
||||||
|
selectedValueIndex: _selectedHourIndex,
|
||||||
|
scrollController: _hourScrollController,
|
||||||
|
isDisabled: (index) => _isDisabled(index, SelectorType.hour),
|
||||||
|
onSelectedItemChanged: (v) => _onSelectedItemChanged(
|
||||||
|
v,
|
||||||
|
SelectorType.hour,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _minuteSelector() {
|
||||||
|
return _selector(
|
||||||
|
values: _timeM,
|
||||||
|
selectedValueIndex: _selectedMinuteIndex,
|
||||||
|
scrollController: _minuteScrollController,
|
||||||
|
isDisabled: (index) => _isDisabled(index, SelectorType.minute),
|
||||||
|
onSelectedItemChanged: (v) => _onSelectedItemChanged(
|
||||||
|
v,
|
||||||
|
SelectorType.minute,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,8 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../../../routes/routes.dart';
|
||||||
|
|
||||||
class GeneralSettings extends StatefulWidget {
|
class GeneralSettings extends StatefulWidget {
|
||||||
const GeneralSettings({Key? key}) : super(key: key);
|
const GeneralSettings({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
|
@ -41,6 +43,15 @@ class _GeneralSettingsState extends State<GeneralSettings> {
|
||||||
int _intervalStart = 0;
|
int _intervalStart = 0;
|
||||||
int _intervalEnd = 24;
|
int _intervalEnd = 24;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
final state = context.read<GeneralSettingsState>();
|
||||||
|
Future.delayed(
|
||||||
|
Duration.zero,
|
||||||
|
() => state.getTime(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Consumer<GeneralSettingsState>(
|
return Consumer<GeneralSettingsState>(
|
||||||
|
|
@ -54,13 +65,39 @@ class _GeneralSettingsState extends State<GeneralSettings> {
|
||||||
DidvanCard(
|
DidvanCard(
|
||||||
child: MenuOption(
|
child: MenuOption(
|
||||||
title: 'زمان دریافت اعلان',
|
title: 'زمان دریافت اعلان',
|
||||||
onTap: () => _pickTimeRange(context),
|
onTap: () => Navigator.of(context).pushNamed(
|
||||||
|
Routes.notificationTime,
|
||||||
|
arguments: {
|
||||||
|
'onTimeChanged': () => Future.delayed(
|
||||||
|
Duration.zero,
|
||||||
|
() => state.getTime(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
icon: DidvanIcons.notification_regular,
|
icon: DidvanIcons.notification_regular,
|
||||||
suffix: 'از${DateTimeUtils.normalizeTimeDuration(
|
suffix: state.time,
|
||||||
Duration(minutes: state.notificationTimeRange[0]),
|
// suffix: 'از${DateTimeUtils.normalizeTimeDuration(
|
||||||
)} تا ${DateTimeUtils.normalizeTimeDuration(
|
// Duration(minutes: state.notificationTimeRange[0]),
|
||||||
Duration(minutes: state.notificationTimeRange[1]),
|
// )} تا ${DateTimeUtils.normalizeTimeDuration(
|
||||||
)}',
|
// Duration(minutes: state.notificationTimeRange[1]),
|
||||||
|
// )}',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
DidvanCard(
|
||||||
|
child: MenuOption(
|
||||||
|
title: 'شخصی سازی محتوا',
|
||||||
|
onTap: () => Navigator.of(context).pushNamed(
|
||||||
|
Routes.favouritesStep,
|
||||||
|
),
|
||||||
|
icon: DidvanIcons.notification_regular,
|
||||||
|
// suffix: 'از${DateTimeUtils.normalizeTimeDuration(
|
||||||
|
// Duration(minutes: state.notificationTimeRange[0]),
|
||||||
|
// )} تا ${DateTimeUtils.normalizeTimeDuration(
|
||||||
|
// Duration(minutes: state.notificationTimeRange[1]),
|
||||||
|
// )}',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const ItemTitle(
|
const ItemTitle(
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,26 @@ class GeneralSettingsState extends CoreProvier {
|
||||||
String _fontFamily = 'Dana-FA';
|
String _fontFamily = 'Dana-FA';
|
||||||
double _fontSizeScale = 1;
|
double _fontSizeScale = 1;
|
||||||
String _brightness = 'light';
|
String _brightness = 'light';
|
||||||
|
String time = "";
|
||||||
|
|
||||||
|
Future<void> getTime() async {
|
||||||
|
appState = AppState.busy;
|
||||||
|
|
||||||
|
final service = RequestService(
|
||||||
|
RequestHelper.notificationTime(),
|
||||||
|
);
|
||||||
|
await service.httpGet();
|
||||||
|
if (service.isSuccess) {
|
||||||
|
time = service.data('time');
|
||||||
|
|
||||||
|
appState = AppState.idle;
|
||||||
|
} else {
|
||||||
|
appState = AppState.failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
set notificationTimeRange(List<int> value) {
|
set notificationTimeRange(List<int> value) {
|
||||||
_notificationTimeRange = value;
|
_notificationTimeRange = value;
|
||||||
|
|
|
||||||
|
|
@ -69,3 +69,6 @@ class _DidvanCheckboxState extends State<DidvanCheckbox> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ dependencies:
|
||||||
universal_html: ^2.0.8
|
universal_html: ^2.0.8
|
||||||
record: ^4.4.3
|
record: ^4.4.3
|
||||||
record_web: ^0.5.0
|
record_web: ^0.5.0
|
||||||
persian_datetime_picker: ^2.4.0
|
persian_datetime_picker: ^2.6.0
|
||||||
persian_number_utility: ^1.1.1
|
persian_number_utility: ^1.1.1
|
||||||
bot_toast: ^4.0.1
|
bot_toast: ^4.0.1
|
||||||
flutter_secure_storage: ^8.0.0
|
flutter_secure_storage: ^8.0.0
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue