Skip to content

Commit 976073e

Browse files
committed
Integrated album group permissions
1 parent 4c727ac commit 976073e

38 files changed

Lines changed: 1118 additions & 395 deletions

l10n/app_en.arb

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,4 @@
11
{
2-
"nWombats": "{count, plural, =0{no wombats} =1{1 wombat} other{{count} wombats}}",
3-
"@nWombats": {
4-
"description": "A plural message",
5-
"placeholders": {
6-
"count": {
7-
"type": "num",
8-
"format": "compact"
9-
}
10-
}
11-
},
12-
132
"tabBar_albums": "Albums",
143
"tabBar_upload": "Upload",
154
"tabBar_preferences": "Settings",
@@ -33,6 +22,7 @@
3322
"loadingHUD_label": "Loading…",
3423
"completeHUD_label": "Complete",
3524
"errorHUD_label": "Error",
25+
"loadMoreHUD_label": "Release to load more",
3626

3727
"uploadRights_title": "Upload Rights Needed",
3828
"uploadRights_message": "You must have upload rights to be able to upload photos or videos.",
@@ -324,6 +314,28 @@
324314
"moveCategoryError_message": "Failed to move your album",
325315

326316

317+
"categoryPrivacy": "Album Privacy",
318+
"categoryPrivacy_subtitle": "Manage access permissions of {album_name} album",
319+
"@categoryPrivacy_subtitle" : {
320+
"placeholders": {
321+
"album_name": {}
322+
}
323+
},
324+
"categoryPrivacyMode_public": "Public",
325+
"categoryPrivacyMode_publicMessage": "Every user can see this album",
326+
"categoryPrivacyMode_private": "Private",
327+
"categoryPrivacyMode_privateMessage": "Visitors must log in and have the necessary permissions to see this album",
328+
"categoryPrivacyGroups": "Group permissions",
329+
"categoryPrivacyGroups_add": "Authorize groups",
330+
"categoryPrivacyUsers": "User permissions",
331+
"categoryPrivacyUsers_message": "{user_count} users automatically have permissions on this album because they are administrators :",
332+
"@categoryPrivacyUsers_message" : {
333+
"placeholders": {
334+
"user_count": {}
335+
}
336+
},
337+
338+
327339
"categorySelection_setThumbnail": "Please select the album which will use the photo {photo} as a thumbnail.",
328340
"@categorySelection_setThumbnail" : {
329341
"placeholders": {
@@ -450,6 +462,18 @@
450462
"tagsAddHUD_label": "Creating Tag…",
451463
"tagsAddHUD_created": "Tag Created",
452464

465+
"group" : "Group",
466+
"groups": "Groups",
467+
"groupsTitle_selectOne": "Select a Group",
468+
"groupsHeader_selected": "Selected",
469+
"groupsHeader_notSelected": "Not Selected",
470+
"groupsHeader_all": "All",
471+
"groupsAdd_title": "Add Group",
472+
"groupsAdd_message": "Enter a name for this new group",
473+
"groupsAdd_placeholder": "New group",
474+
"groupsAddHUD_label": "Creating Group…",
475+
"groupsAddHUD_created": "Group Created",
476+
453477

454478
"tagsAddError_message": "Failed to create new tag",
455479
"tagsAddError_title": "Create Fail",

lib/app.dart

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,23 @@ import 'package:piwigo_ng/services/app_providers.dart';
77
import 'package:piwigo_ng/services/preferences_service.dart';
88
import 'package:piwigo_ng/utils/overscroll_behavior.dart';
99
import 'package:piwigo_ng/utils/themes.dart';
10+
import 'package:piwigo_ng/views/album/album_privacy_page.dart';
1011
import 'package:piwigo_ng/views/album/album_view_page.dart';
11-
import 'package:piwigo_ng/views/album/root_album_view_page.dart';
12+
import 'package:piwigo_ng/views/album/root_album_page.dart';
13+
import 'package:piwigo_ng/views/authentication/login_page.dart';
1214
import 'package:piwigo_ng/views/authentication/login_settings_page.dart';
13-
import 'package:piwigo_ng/views/authentication/login_view_page.dart';
1415
import 'package:piwigo_ng/views/image/edit_image_page.dart';
1516
import 'package:piwigo_ng/views/image/image_favorites_page.dart';
16-
import 'package:piwigo_ng/views/image/image_search_view_page.dart';
17-
import 'package:piwigo_ng/views/image/image_view_page.dart';
17+
import 'package:piwigo_ng/views/image/image_page.dart';
18+
import 'package:piwigo_ng/views/image/image_search_page.dart';
1819
import 'package:piwigo_ng/views/image/video_player_page.dart';
1920
import 'package:piwigo_ng/views/settings/auto_upload_page.dart';
20-
import 'package:piwigo_ng/views/settings/privacy_policy_view_page.dart';
21-
import 'package:piwigo_ng/views/settings/select_language_view_page.dart';
22-
import 'package:piwigo_ng/views/settings/settings_view_page.dart';
21+
import 'package:piwigo_ng/views/settings/privacy_policy_page.dart';
22+
import 'package:piwigo_ng/views/settings/select_language_page.dart';
23+
import 'package:piwigo_ng/views/settings/settings_page.dart';
2324
import 'package:piwigo_ng/views/unknown_route_page.dart';
25+
import 'package:piwigo_ng/views/upload/upload_page.dart';
2426
import 'package:piwigo_ng/views/upload/upload_status_page.dart';
25-
import 'package:piwigo_ng/views/upload/upload_view_page.dart';
2627

2728
import 'models/image_model.dart';
2829

@@ -78,7 +79,7 @@ class App extends StatelessWidget {
7879
onGenerateInitialRoutes: (String route) {
7980
return [
8081
MaterialPageRoute(
81-
builder: (_) => const LoginViewPage(autoLogin: true),
82+
builder: (_) => const LoginPage(autoLogin: true),
8283
),
8384
];
8485
},
@@ -106,35 +107,42 @@ Route<dynamic> generateRoute(RouteSettings settings) {
106107
}
107108

108109
switch (settings.name) {
109-
case LoginViewPage.routeName:
110+
case LoginPage.routeName:
110111
return MaterialPageRoute(
111-
builder: (_) => const LoginViewPage(),
112+
builder: (_) => const LoginPage(),
112113
settings: settings,
113114
);
114115
case LoginSettingsPage.routeName:
115116
return MaterialPageRoute(
116117
builder: (_) => LoginSettingsPage(),
117118
settings: settings,
118119
);
119-
case RootAlbumViewPage.routeName:
120+
case RootAlbumPage.routeName:
120121
return MaterialPageRoute(
121-
builder: (_) => RootAlbumViewPage(
122+
builder: (_) => RootAlbumPage(
122123
albumId: arguments['albumId'] ?? 0,
123124
isAdmin: arguments['isAdmin'] ?? isAdmin,
124125
),
125126
settings: settings,
126127
);
127-
case AlbumViewPage.routeName:
128+
case AlbumPage.routeName:
128129
return MaterialPageRoute(
129-
builder: (_) => AlbumViewPage(
130+
builder: (_) => AlbumPage(
130131
album: arguments['album'],
131132
isAdmin: arguments['isAdmin'] ?? isAdmin,
132133
),
133134
settings: settings,
134135
);
135-
case ImageSearchViewPage.routeName:
136+
case AlbumPrivacyPage.routeName:
136137
return MaterialPageRoute(
137-
builder: (_) => ImageSearchViewPage(
138+
builder: (_) => AlbumPrivacyPage(
139+
album: arguments['album']!,
140+
),
141+
settings: settings,
142+
);
143+
case ImageSearchPage.routeName:
144+
return MaterialPageRoute(
145+
builder: (_) => ImageSearchPage(
138146
isAdmin: arguments['isAdmin'] ?? isAdmin,
139147
),
140148
settings: settings,
@@ -146,9 +154,9 @@ Route<dynamic> generateRoute(RouteSettings settings) {
146154
),
147155
settings: settings,
148156
);
149-
case UploadViewPage.routeName:
157+
case UploadPage.routeName:
150158
return MaterialPageRoute(
151-
builder: (_) => UploadViewPage(
159+
builder: (_) => UploadPage(
152160
imageList: arguments["images"] ?? <XFile>[],
153161
albumId: arguments["category"],
154162
),
@@ -164,9 +172,9 @@ Route<dynamic> generateRoute(RouteSettings settings) {
164172
builder: (_) => AutoUploadPage(),
165173
settings: settings,
166174
);
167-
case ImageViewPage.routeName:
175+
case ImagePage.routeName:
168176
return MaterialPageRoute<List<ImageModel>?>(
169-
builder: (_) => ImageViewPage(
177+
builder: (_) => ImagePage(
170178
images: arguments['images'] ?? [],
171179
startId: arguments['startId'],
172180
album: arguments['album'],
@@ -189,19 +197,19 @@ Route<dynamic> generateRoute(RouteSettings settings) {
189197
),
190198
settings: settings,
191199
);
192-
case SettingsViewPage.routeName:
200+
case SettingsPage.routeName:
193201
return MaterialPageRoute(
194-
builder: (_) => SettingsViewPage(),
202+
builder: (_) => SettingsPage(),
195203
settings: settings,
196204
);
197-
case PrivacyPolicyViewPage.routeName:
205+
case PrivacyPolicyPage.routeName:
198206
return MaterialPageRoute(
199-
builder: (_) => const PrivacyPolicyViewPage(),
207+
builder: (_) => const PrivacyPolicyPage(),
200208
settings: settings,
201209
);
202-
case SelectLanguageViewPage.routeName:
210+
case SelectLanguagePage.routeName:
203211
return MaterialPageRoute(
204-
builder: (_) => const SelectLanguageViewPage(),
212+
builder: (_) => const SelectLanguagePage(),
205213
settings: settings,
206214
);
207215
default:

lib/components/appbars/root_search_app_bar.dart

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import 'package:piwigo_ng/views/image/image_favorites_page.dart';
88
import 'package:piwigo_ng/views/upload/upload_status_page.dart';
99
import 'package:provider/provider.dart';
1010

11-
import '../../views/settings/settings_view_page.dart';
11+
import '../../views/settings/settings_page.dart';
1212
import '../fields/app_field.dart';
1313

1414
class RootSearchAppBar extends StatefulWidget {
@@ -40,7 +40,9 @@ class _RootSearchAppBarState extends State<RootSearchAppBar> {
4040
if (widget.scrollController.offset > _expandedHeight * _opacityScale) {
4141
return 0.0;
4242
}
43-
return (_expandedHeight * _opacityScale - widget.scrollController.offset) / (_expandedHeight * _opacityScale);
43+
return (_expandedHeight * _opacityScale -
44+
widget.scrollController.offset) /
45+
(_expandedHeight * _opacityScale);
4446
}
4547
return 1.0;
4648
}
@@ -56,7 +58,8 @@ class _RootSearchAppBarState extends State<RootSearchAppBar> {
5658
}
5759

5860
// In case 0%-100% of the expanded height is viewed
59-
double scrollDelta = (_expandedHeight - widget.scrollController.offset) / _expandedHeight;
61+
double scrollDelta =
62+
(_expandedHeight - widget.scrollController.offset) / _expandedHeight;
6063
double scrollPercent = (scrollDelta * 2 - 1);
6164
return (1 - scrollPercent) * delta * basePadding + basePadding;
6265
}
@@ -68,7 +71,8 @@ class _RootSearchAppBarState extends State<RootSearchAppBar> {
6871
Widget build(BuildContext context) {
6972
return SliverAppBar(
7073
leading: IconButton(
71-
onPressed: () => Navigator.of(context).pushNamed(SettingsViewPage.routeName),
74+
onPressed: () =>
75+
Navigator.of(context).pushNamed(SettingsPage.routeName),
7276
icon: const Icon(Icons.settings),
7377
),
7478
pinned: true,
@@ -121,7 +125,8 @@ class _RootSearchAppBarState extends State<RootSearchAppBar> {
121125
PopupMenuItem(
122126
onTap: () => Future.delayed(
123127
const Duration(seconds: 0),
124-
() => Navigator.of(context).pushNamed(UploadStatusPage.routeName),
128+
() =>
129+
Navigator.of(context).pushNamed(UploadStatusPage.routeName),
125130
),
126131
child: Stack(
127132
children: [
@@ -132,7 +137,8 @@ class _RootSearchAppBarState extends State<RootSearchAppBar> {
132137
Positioned(
133138
top: 14.0,
134139
left: 0.0,
135-
child: Consumer<UploadNotifier>(builder: (context, uploadNotifier, child) {
140+
child: Consumer<UploadNotifier>(
141+
builder: (context, uploadNotifier, child) {
136142
return NotificationDot(
137143
isShown: uploadNotifier.uploadList.isNotEmpty,
138144
);
@@ -145,7 +151,8 @@ class _RootSearchAppBarState extends State<RootSearchAppBar> {
145151
PopupMenuItem(
146152
onTap: () => Future.delayed(
147153
const Duration(seconds: 0),
148-
() => Navigator.of(context).pushNamed(ImageFavoritesPage.routeName),
154+
() => Navigator.of(context)
155+
.pushNamed(ImageFavoritesPage.routeName),
149156
),
150157
child: PopupListItem(
151158
icon: Icons.favorite,
@@ -157,7 +164,8 @@ class _RootSearchAppBarState extends State<RootSearchAppBar> {
157164
Positioned(
158165
top: 12.0,
159166
left: 12.0,
160-
child: Consumer<UploadNotifier>(builder: (context, uploadNotifier, child) {
167+
child: Consumer<UploadNotifier>(
168+
builder: (context, uploadNotifier, child) {
161169
return NotificationDot(
162170
isShown: uploadNotifier.uploadList.isNotEmpty,
163171
);
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:piwigo_ng/utils/resources.dart';
3+
4+
class SelectChip extends StatelessWidget {
5+
const SelectChip({
6+
Key? key,
7+
required this.label,
8+
this.onTap,
9+
this.icon,
10+
this.selected = false,
11+
}) : super(key: key);
12+
13+
final Widget? icon;
14+
final bool selected;
15+
final String label;
16+
final Function()? onTap;
17+
18+
@override
19+
Widget build(BuildContext context) {
20+
return FilterChip(
21+
elevation: .0,
22+
side: BorderSide.none,
23+
labelStyle: TextStyle(
24+
fontSize: 14,
25+
color: selected
26+
? AppColors.white
27+
: Theme.of(context).textTheme.bodyMedium!.color,
28+
),
29+
backgroundColor: Theme.of(context).chipTheme.backgroundColor,
30+
checkmarkColor: AppColors.white,
31+
selected: selected,
32+
onSelected: (_) => onTap?.call(),
33+
label: Text(label),
34+
);
35+
}
36+
}
37+
38+
class PiwigoChip extends StatelessWidget {
39+
const PiwigoChip({
40+
Key? key,
41+
required this.label,
42+
this.onRemove,
43+
this.backgroundColor,
44+
this.foregroundColor,
45+
}) : super(key: key);
46+
47+
final String label;
48+
final Function()? onRemove;
49+
final Color? backgroundColor;
50+
final Color? foregroundColor;
51+
52+
@override
53+
Widget build(BuildContext context) {
54+
return Chip(
55+
elevation: .0,
56+
side: BorderSide.none,
57+
backgroundColor: Theme.of(context).colorScheme.secondary,
58+
deleteIconColor: AppColors.white,
59+
label: Text(label),
60+
labelStyle: TextStyle(
61+
fontSize: 14,
62+
color: AppColors.white,
63+
),
64+
onDeleted: () => onRemove?.call(),
65+
);
66+
}
67+
}

0 commit comments

Comments
 (0)