fix(windows): improve minimized sidebar layout and replace logo with expand icon
This commit is contained in:
1 parent
9c341bab54
commit
418218fa94
1 file changed
+196
-112
@@ -197,9 +197,14 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
color: isSelected
|
color: isSelected
|
||||||
? AppColors.primaryGreen.withValues(alpha: 0.12)
|
? AppColors.primaryGreen.withValues(alpha: 0.12)
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(8),
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
hoverColor: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSurface
|
||||||
|
.withValues(alpha: 0.05),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_isTabLoading = true;
|
_isTabLoading = true;
|
||||||
@@ -222,12 +227,42 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
.setTab(tab['label'] as String);
|
.setTab(tab['label'] as String);
|
||||||
_reloadTabContent(tab['label'] as String);
|
_reloadTabContent(tab['label'] as String);
|
||||||
},
|
},
|
||||||
child: SingleChildScrollView(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 236,
|
height: 42,
|
||||||
child: Padding(
|
child: _isMinimized
|
||||||
|
? Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
if (isSelected)
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
child: Container(
|
||||||
|
width: 3.5,
|
||||||
|
height: 20,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.primaryGreen,
|
||||||
|
borderRadius: BorderRadius.circular(2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Center(
|
||||||
|
child: Icon(
|
||||||
|
(isSelected
|
||||||
|
? tab['activeIcon'] ?? tab['icon']
|
||||||
|
: tab['icon'])
|
||||||
|
as IconData,
|
||||||
|
color: isSelected
|
||||||
|
? AppColors.primaryGreen
|
||||||
|
: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSurface
|
||||||
|
.withValues(alpha: 0.65),
|
||||||
|
size: 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 14.0,
|
horizontal: 14.0,
|
||||||
vertical: 9.0,
|
vertical: 9.0,
|
||||||
@@ -244,14 +279,11 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
: Theme.of(context)
|
: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.onSurface
|
.onSurface
|
||||||
.withValues(alpha: 0.6),
|
.withValues(alpha: 0.65),
|
||||||
size: 20,
|
size: 20,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 14),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: AnimatedOpacity(
|
|
||||||
duration: const Duration(milliseconds: 200),
|
|
||||||
opacity: _isMinimized ? 0.0 : 1.0,
|
|
||||||
child: Text(
|
child: Text(
|
||||||
tab['label'] as String,
|
tab['label'] as String,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@@ -270,7 +302,6 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -279,7 +310,6 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -445,9 +475,9 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
// WINDOWS SIDEBAR (Fixed Width: 260px)
|
// WINDOWS SIDEBAR (Fixed Width: 260px)
|
||||||
// ==========================================
|
// ==========================================
|
||||||
AnimatedContainer(
|
AnimatedContainer(
|
||||||
duration: const Duration(milliseconds: 400),
|
duration: const Duration(milliseconds: 250),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOutCubic,
|
||||||
width: _isMinimized ? 80 : 260,
|
width: _isMinimized ? 72 : 260,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.surface,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
border: Border(
|
border: Border(
|
||||||
@@ -459,26 +489,59 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
SingleChildScrollView(
|
// ==========================================
|
||||||
scrollDirection: Axis.horizontal,
|
// SIDEBAR HEADER: EXPAND BUTTON (MINIMIZED) OR LOGO + TITLE + COLLAPSE
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
// ==========================================
|
||||||
child: SizedBox(
|
_isMinimized
|
||||||
width: 260,
|
? Padding(
|
||||||
child: Padding(
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 14.0,
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Tooltip(
|
||||||
|
message: 'Expand Sidebar',
|
||||||
|
waitDuration:
|
||||||
|
const Duration(milliseconds: 300),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: InkWell(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
hoverColor: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSurface
|
||||||
|
.withValues(alpha: 0.08),
|
||||||
|
onTap: () {
|
||||||
|
setState(() => _isMinimized = false);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Icon(
|
||||||
|
Icons.view_sidebar_outlined,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSurface
|
||||||
|
.withValues(alpha: 0.8),
|
||||||
|
size: 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(
|
padding: const EdgeInsets.fromLTRB(
|
||||||
20,
|
18,
|
||||||
20,
|
|
||||||
14,
|
14,
|
||||||
12,
|
12,
|
||||||
|
12,
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
|
||||||
if (_isMinimized) {
|
|
||||||
setState(() => _isMinimized = false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onLongPressStart: (_) {
|
onLongPressStart: (_) {
|
||||||
_holdTimer = Timer(
|
_holdTimer = Timer(
|
||||||
const Duration(seconds: 3),
|
const Duration(seconds: 3),
|
||||||
@@ -487,12 +550,14 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onLongPressEnd: (_) => _holdTimer?.cancel(),
|
onLongPressEnd: (_) =>
|
||||||
|
_holdTimer?.cancel(),
|
||||||
onLongPressCancel: () =>
|
onLongPressCancel: () =>
|
||||||
_holdTimer?.cancel(),
|
_holdTimer?.cancel(),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius:
|
||||||
|
BorderRadius.circular(8),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withValues(
|
color: Colors.black.withValues(
|
||||||
@@ -504,69 +569,76 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius:
|
||||||
|
BorderRadius.circular(8),
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
'assets/images/logo.webp',
|
'assets/images/logo.webp',
|
||||||
width: 36,
|
width: 32,
|
||||||
height: 36,
|
height: 32,
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 10),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: AnimatedOpacity(
|
|
||||||
duration: const Duration(
|
|
||||||
milliseconds: 200,
|
|
||||||
),
|
|
||||||
opacity: _isMinimized ? 0.0 : 1.0,
|
|
||||||
child: Text(
|
child: Text(
|
||||||
'TIS RMS',
|
'TIS RMS',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 17,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.onSurface,
|
.onSurface,
|
||||||
letterSpacing: 1.2,
|
letterSpacing: 1.1,
|
||||||
),
|
),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Tooltip(
|
||||||
AnimatedOpacity(
|
message: 'Collapse Sidebar',
|
||||||
duration: const Duration(milliseconds: 200),
|
waitDuration:
|
||||||
opacity: _isMinimized ? 0.0 : 1.0,
|
const Duration(milliseconds: 300),
|
||||||
child: IconButton(
|
child: Material(
|
||||||
icon: Icon(
|
color: Colors.transparent,
|
||||||
Icons.menu,
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: InkWell(
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(8),
|
||||||
|
hoverColor: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSurface
|
||||||
|
.withValues(alpha: 0.08),
|
||||||
|
onTap: () {
|
||||||
|
setState(() => _isMinimized = true);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Icon(
|
||||||
|
Icons.view_sidebar_rounded,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.onSurface
|
.onSurface
|
||||||
.withValues(alpha: 0.6),
|
.withValues(alpha: 0.65),
|
||||||
|
size: 21,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
|
||||||
if (!_isMinimized) {
|
|
||||||
setState(() => _isMinimized = true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tooltip: 'Minimize Sidebar',
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 6),
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
|
|
||||||
// Navigation Items: Single Unified Scrollable List
|
// Navigation Items: Single Unified Scrollable List
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
horizontal: 12,
|
horizontal: _isMinimized ? 12 : 12,
|
||||||
vertical: 4,
|
vertical: 4,
|
||||||
),
|
),
|
||||||
itemCount: tabs.length,
|
itemCount: tabs.length,
|
||||||
@@ -592,7 +664,7 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
// Persistent Server Connection Status Pill
|
// Persistent Server Connection Status Pill
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
horizontal: _isMinimized ? 12 : 20,
|
horizontal: _isMinimized ? 8 : 20,
|
||||||
vertical: 8,
|
vertical: 8,
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
@@ -605,38 +677,31 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
height: 1,
|
height: 1,
|
||||||
color: Theme.of(context).dividerColor,
|
color: Theme.of(context).dividerColor,
|
||||||
),
|
),
|
||||||
SingleChildScrollView(
|
_isMinimized
|
||||||
scrollDirection: Axis.horizontal,
|
? Padding(
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
padding:
|
||||||
child: SizedBox(
|
const EdgeInsets.symmetric(vertical: 12.0),
|
||||||
width: 260,
|
child: Center(
|
||||||
child: Padding(
|
child: Tooltip(
|
||||||
padding: const EdgeInsets.symmetric(
|
message: ref
|
||||||
horizontal: 18.0,
|
.watch(authProvider)
|
||||||
vertical: 12.0,
|
.value
|
||||||
),
|
?.fullName ??
|
||||||
child: Row(
|
'User Profile',
|
||||||
children: [
|
waitDuration:
|
||||||
GestureDetector(
|
const Duration(milliseconds: 300),
|
||||||
onTap: () {
|
|
||||||
if (_isMinimized) {
|
|
||||||
setState(() => _isMinimized = false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
final user = ref
|
final user =
|
||||||
.watch(authProvider)
|
ref.watch(authProvider).value;
|
||||||
.value;
|
final initials = user != null &&
|
||||||
final initials =
|
|
||||||
user != null &&
|
|
||||||
user.firstName.isNotEmpty &&
|
user.firstName.isNotEmpty &&
|
||||||
user.lastName.isNotEmpty
|
user.lastName.isNotEmpty
|
||||||
? '${user.firstName[0]}${user.lastName[0]}'
|
? '${user.firstName[0]}${user.lastName[0]}'
|
||||||
.toUpperCase()
|
.toUpperCase()
|
||||||
: 'SA';
|
: 'SA';
|
||||||
return CircleAvatar(
|
return CircleAvatar(
|
||||||
radius: 20,
|
radius: 18,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
AppColors.primaryGreen,
|
AppColors.primaryGreen,
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -644,23 +709,53 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 16,
|
fontSize: 13,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
|
||||||
Expanded(
|
|
||||||
child: AnimatedOpacity(
|
|
||||||
duration: const Duration(
|
|
||||||
milliseconds: 200,
|
|
||||||
),
|
),
|
||||||
opacity: _isMinimized ? 0.0 : 1.0,
|
)
|
||||||
|
: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 14.0,
|
||||||
|
vertical: 12.0,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final user =
|
||||||
|
ref.watch(authProvider).value;
|
||||||
|
final initials = user != null &&
|
||||||
|
user.firstName.isNotEmpty &&
|
||||||
|
user.lastName.isNotEmpty
|
||||||
|
? '${user.firstName[0]}${user.lastName[0]}'
|
||||||
|
.toUpperCase()
|
||||||
|
: 'SA';
|
||||||
|
return CircleAvatar(
|
||||||
|
radius: 18,
|
||||||
|
backgroundColor:
|
||||||
|
AppColors.primaryGreen,
|
||||||
|
child: Text(
|
||||||
|
initials,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 13,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment:
|
crossAxisAlignment:
|
||||||
CrossAxisAlignment.start,
|
CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
ref
|
ref
|
||||||
@@ -670,7 +765,7 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
'Unknown User',
|
'Unknown User',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 14,
|
fontSize: 13,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.onSurface,
|
.onSurface,
|
||||||
@@ -681,7 +776,7 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
Text(
|
Text(
|
||||||
widget.userRole.toUpperCase(),
|
widget.userRole.toUpperCase(),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 11,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.onSurface
|
.onSurface
|
||||||
@@ -691,50 +786,39 @@ class _WindowsSidebarLayoutState extends ConsumerState<WindowsSidebarLayout> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
IconButton(
|
||||||
AnimatedOpacity(
|
|
||||||
duration: const Duration(milliseconds: 200),
|
|
||||||
opacity: _isMinimized ? 0.0 : 1.0,
|
|
||||||
child: IconButton(
|
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.menu_book_outlined,
|
Icons.menu_book_outlined,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.onSurface
|
.onSurface
|
||||||
.withValues(alpha: 0.6),
|
.withValues(alpha: 0.6),
|
||||||
|
size: 19,
|
||||||
),
|
),
|
||||||
tooltip: 'User Guide & Documentation',
|
tooltip: 'User Guide & Documentation',
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (!_isMinimized) {
|
|
||||||
DocumentationScreen.open(context);
|
DocumentationScreen.open(context);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
IconButton(
|
||||||
AnimatedOpacity(
|
|
||||||
duration: const Duration(milliseconds: 200),
|
|
||||||
opacity: _isMinimized ? 0.0 : 1.0,
|
|
||||||
child: IconButton(
|
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.logout,
|
Icons.logout,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.onSurface
|
.onSurface
|
||||||
.withValues(alpha: 0.6),
|
.withValues(alpha: 0.6),
|
||||||
|
size: 19,
|
||||||
),
|
),
|
||||||
tooltip: 'Logout',
|
tooltip: 'Logout',
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (!_isMinimized) {
|
|
||||||
showLogoutConfirmationDialog(context);
|
showLogoutConfirmationDialog(context);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in new issue
Block a user