Update shared collections interface
This commit is contained in:
parent
989594f1ef
commit
96dba3f905
8 changed files with 243 additions and 92 deletions
|
@ -1,3 +1,4 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:path/path.dart';
|
||||
|
@ -12,15 +13,14 @@ class CollectionsDB {
|
|||
static final collectionsTable = 'collections';
|
||||
|
||||
static final columnID = 'collection_id';
|
||||
static final columnOwnerID = 'owner_id';
|
||||
static final columnOwnerEmail = 'owner_email';
|
||||
static final columnOwnerName = 'owner_name';
|
||||
static final columnOwner = 'owner';
|
||||
static final columnEncryptedKey = 'encrypted_key';
|
||||
static final columnKeyDecryptionNonce = 'key_decryption_nonce';
|
||||
static final columnName = 'name';
|
||||
static final columnType = 'type';
|
||||
static final columnEncryptedPath = 'encrypted_path';
|
||||
static final columnPathDecryptionNonce = 'path_decryption_nonce';
|
||||
static final columnSharees = 'sharees';
|
||||
static final columnUpdationTime = 'updation_time';
|
||||
|
||||
CollectionsDB._privateConstructor();
|
||||
|
@ -47,15 +47,14 @@ class CollectionsDB {
|
|||
await db.execute('''
|
||||
CREATE TABLE $collectionsTable (
|
||||
$columnID INTEGER PRIMARY KEY NOT NULL,
|
||||
$columnOwnerID INTEGER NOT NULL,
|
||||
$columnOwnerEmail TEXT,
|
||||
$columnOwnerName TEXT,
|
||||
$columnOwner TEXT NOT NULL,
|
||||
$columnEncryptedKey TEXT NOT NULL,
|
||||
$columnKeyDecryptionNonce TEXT,
|
||||
$columnName TEXT NOT NULL,
|
||||
$columnType TEXT NOT NULL,
|
||||
$columnEncryptedPath TEXT,
|
||||
$columnPathDecryptionNonce TEXT,
|
||||
$columnSharees TEXT,
|
||||
$columnUpdationTime TEXT NOT NULL
|
||||
)
|
||||
''');
|
||||
|
@ -107,15 +106,15 @@ class CollectionsDB {
|
|||
Map<String, dynamic> _getRowForCollection(Collection collection) {
|
||||
var row = new Map<String, dynamic>();
|
||||
row[columnID] = collection.id;
|
||||
row[columnOwnerID] = collection.owner.id;
|
||||
row[columnOwnerEmail] = collection.owner.email;
|
||||
row[columnOwnerName] = collection.owner.name;
|
||||
row[columnOwner] = collection.owner.toJson();
|
||||
row[columnEncryptedKey] = collection.encryptedKey;
|
||||
row[columnKeyDecryptionNonce] = collection.keyDecryptionNonce;
|
||||
row[columnName] = collection.name;
|
||||
row[columnType] = Collection.typeToString(collection.type);
|
||||
row[columnEncryptedPath] = collection.attributes.encryptedPath;
|
||||
row[columnPathDecryptionNonce] = collection.attributes.pathDecryptionNonce;
|
||||
row[columnSharees] =
|
||||
json.encode(collection.sharees?.map((x) => x?.toMap())?.toList());
|
||||
row[columnUpdationTime] = collection.updationTime;
|
||||
return row;
|
||||
}
|
||||
|
@ -123,11 +122,7 @@ class CollectionsDB {
|
|||
Collection _convertToCollection(Map<String, dynamic> row) {
|
||||
return Collection(
|
||||
row[columnID],
|
||||
CollectionOwner(
|
||||
id: row[columnOwnerID],
|
||||
email: row[columnOwnerEmail],
|
||||
name: row[columnOwnerName],
|
||||
),
|
||||
User.fromJson(row[columnOwner]),
|
||||
row[columnEncryptedKey],
|
||||
row[columnKeyDecryptionNonce],
|
||||
row[columnName],
|
||||
|
@ -135,6 +130,8 @@ class CollectionsDB {
|
|||
CollectionAttributes(
|
||||
encryptedPath: row[columnEncryptedPath],
|
||||
pathDecryptionNonce: row[columnPathDecryptionNonce]),
|
||||
List<User>.from((json.decode(row[columnSharees]) as List)
|
||||
.map((x) => User.fromMap(x))),
|
||||
int.parse(row[columnUpdationTime]),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class Collection {
|
||||
final int id;
|
||||
final CollectionOwner owner;
|
||||
final User owner;
|
||||
final String encryptedKey;
|
||||
final String keyDecryptionNonce;
|
||||
final String name;
|
||||
final CollectionType type;
|
||||
final CollectionAttributes attributes;
|
||||
final List<User> sharees;
|
||||
final int updationTime;
|
||||
final bool isDeleted;
|
||||
|
||||
|
@ -19,6 +22,7 @@ class Collection {
|
|||
this.name,
|
||||
this.type,
|
||||
this.attributes,
|
||||
this.sharees,
|
||||
this.updationTime, {
|
||||
this.isDeleted = false,
|
||||
});
|
||||
|
@ -44,6 +48,32 @@ class Collection {
|
|||
}
|
||||
}
|
||||
|
||||
Collection copyWith({
|
||||
int id,
|
||||
User owner,
|
||||
String encryptedKey,
|
||||
String keyDecryptionNonce,
|
||||
String name,
|
||||
CollectionType type,
|
||||
CollectionAttributes attributes,
|
||||
List<User> sharees,
|
||||
int updationTime,
|
||||
bool isDeleted,
|
||||
}) {
|
||||
return Collection(
|
||||
id ?? this.id,
|
||||
owner ?? this.owner,
|
||||
encryptedKey ?? this.encryptedKey,
|
||||
keyDecryptionNonce ?? this.keyDecryptionNonce,
|
||||
name ?? this.name,
|
||||
type ?? this.type,
|
||||
attributes ?? this.attributes,
|
||||
sharees ?? this.sharees,
|
||||
updationTime ?? this.updationTime,
|
||||
isDeleted: isDeleted ?? this.isDeleted,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
|
@ -53,21 +83,26 @@ class Collection {
|
|||
'name': name,
|
||||
'type': typeToString(type),
|
||||
'attributes': attributes?.toMap(),
|
||||
'sharees': sharees?.map((x) => x?.toMap())?.toList(),
|
||||
'updationTime': updationTime,
|
||||
'isDeleted': isDeleted,
|
||||
};
|
||||
}
|
||||
|
||||
factory Collection.fromMap(Map<String, dynamic> map) {
|
||||
if (map == null) return null;
|
||||
|
||||
final sharees = (map['sharees'] == null || map['sharees'].length == 0)
|
||||
? List<User>()
|
||||
: List<User>.from(map['sharees'].map((x) => User.fromMap(x)));
|
||||
return Collection(
|
||||
map['id'],
|
||||
CollectionOwner.fromMap(map['owner']),
|
||||
User.fromMap(map['owner']),
|
||||
map['encryptedKey'],
|
||||
map['keyDecryptionNonce'],
|
||||
map['name'],
|
||||
typeFromString(map['type']),
|
||||
CollectionAttributes.fromMap(map['attributes']),
|
||||
sharees,
|
||||
map['updationTime'],
|
||||
isDeleted: map['isDeleted'] ?? false,
|
||||
);
|
||||
|
@ -80,7 +115,7 @@ class Collection {
|
|||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Collection(id: $id, owner: ${owner.toString()} encryptedKey: $encryptedKey, keyDecryptionNonce: $keyDecryptionNonce, name: $name, type: $type, attributes: $attributes, creationTime: $updationTime)';
|
||||
return 'Collection(id: $id, owner: $owner, encryptedKey: $encryptedKey, keyDecryptionNonce: $keyDecryptionNonce, name: $name, type: $type, attributes: $attributes, sharees: $sharees, updationTime: $updationTime, isDeleted: $isDeleted)';
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -95,7 +130,9 @@ class Collection {
|
|||
o.name == name &&
|
||||
o.type == type &&
|
||||
o.attributes == attributes &&
|
||||
o.updationTime == updationTime;
|
||||
listEquals(o.sharees, sharees) &&
|
||||
o.updationTime == updationTime &&
|
||||
o.isDeleted == isDeleted;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -107,7 +144,9 @@ class Collection {
|
|||
name.hashCode ^
|
||||
type.hashCode ^
|
||||
attributes.hashCode ^
|
||||
updationTime.hashCode;
|
||||
sharees.hashCode ^
|
||||
updationTime.hashCode ^
|
||||
isDeleted.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,23 +217,23 @@ class CollectionAttributes {
|
|||
int get hashCode => encryptedPath.hashCode ^ pathDecryptionNonce.hashCode;
|
||||
}
|
||||
|
||||
class CollectionOwner {
|
||||
class User {
|
||||
int id;
|
||||
String email;
|
||||
String name;
|
||||
|
||||
CollectionOwner({
|
||||
User({
|
||||
this.id,
|
||||
this.email,
|
||||
this.name,
|
||||
});
|
||||
|
||||
CollectionOwner copyWith({
|
||||
User copyWith({
|
||||
int id,
|
||||
String email,
|
||||
String name,
|
||||
}) {
|
||||
return CollectionOwner(
|
||||
return User(
|
||||
id: id ?? this.id,
|
||||
email: email ?? this.email,
|
||||
name: name ?? this.name,
|
||||
|
@ -209,10 +248,10 @@ class CollectionOwner {
|
|||
};
|
||||
}
|
||||
|
||||
factory CollectionOwner.fromMap(Map<String, dynamic> map) {
|
||||
factory User.fromMap(Map<String, dynamic> map) {
|
||||
if (map == null) return null;
|
||||
|
||||
return CollectionOwner(
|
||||
return User(
|
||||
id: map['id'],
|
||||
email: map['email'],
|
||||
name: map['name'],
|
||||
|
@ -221,8 +260,7 @@ class CollectionOwner {
|
|||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory CollectionOwner.fromJson(String source) =>
|
||||
CollectionOwner.fromMap(json.decode(source));
|
||||
factory User.fromJson(String source) => User.fromMap(json.decode(source));
|
||||
|
||||
@override
|
||||
String toString() => 'CollectionOwner(id: $id, email: $email, name: $name)';
|
||||
|
@ -231,10 +269,7 @@ class CollectionOwner {
|
|||
bool operator ==(Object o) {
|
||||
if (identical(this, o)) return true;
|
||||
|
||||
return o is CollectionOwner &&
|
||||
o.id == id &&
|
||||
o.email == email &&
|
||||
o.name == name;
|
||||
return o is User && o.id == id && o.email == email && o.name == name;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -20,3 +20,10 @@ class CollectionWithThumbnail {
|
|||
this.lastUpdatedFile,
|
||||
);
|
||||
}
|
||||
|
||||
class SharedCollections {
|
||||
final List<CollectionWithThumbnail> outgoing;
|
||||
final List<CollectionWithThumbnail> incoming;
|
||||
|
||||
SharedCollections(this.outgoing, this.incoming);
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ class CollectionsService {
|
|||
return _collectionIDToCollections.values.toList();
|
||||
}
|
||||
|
||||
Future<List<String>> getSharees(int collectionID) {
|
||||
Future<List<User>> getSharees(int collectionID) {
|
||||
return Dio()
|
||||
.get(
|
||||
Configuration.instance.getHttpEndpoint() + "/collections/sharees",
|
||||
|
@ -90,27 +90,29 @@ class CollectionsService {
|
|||
)
|
||||
.then((response) {
|
||||
_logger.info(response.toString());
|
||||
final emails = List<String>();
|
||||
for (final email in response.data["emails"]) {
|
||||
emails.add(email);
|
||||
final sharees = List<User>();
|
||||
for (final user in response.data["sharees"]) {
|
||||
sharees.add(User.fromMap(user));
|
||||
}
|
||||
return emails;
|
||||
return sharees;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> share(int collectionID, String email, String publicKey) {
|
||||
final encryptedKey = CryptoUtil.sealSync(
|
||||
getCollectionKey(collectionID), Sodium.base642bin(publicKey));
|
||||
return Dio().post(
|
||||
Configuration.instance.getHttpEndpoint() + "/collections/share",
|
||||
data: {
|
||||
"collectionID": collectionID,
|
||||
"email": email,
|
||||
"encryptedKey": Sodium.bin2base64(encryptedKey),
|
||||
},
|
||||
options:
|
||||
Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
|
||||
);
|
||||
return Dio()
|
||||
.post(
|
||||
Configuration.instance.getHttpEndpoint() + "/collections/share",
|
||||
data: {
|
||||
"collectionID": collectionID,
|
||||
"email": email,
|
||||
"encryptedKey": Sodium.bin2base64(encryptedKey),
|
||||
},
|
||||
options: Options(
|
||||
headers: {"X-Auth-Token": Configuration.instance.getToken()}),
|
||||
)
|
||||
.then((value) => sync());
|
||||
}
|
||||
|
||||
Future<void> unshare(int collectionID, String email) {
|
||||
|
@ -183,6 +185,7 @@ class CollectionsService {
|
|||
CollectionType.album,
|
||||
CollectionAttributes(),
|
||||
null,
|
||||
null,
|
||||
));
|
||||
return collection;
|
||||
}
|
||||
|
@ -206,6 +209,7 @@ class CollectionsService {
|
|||
encryptedPath: Sodium.bin2base64(encryptedPath.encryptedData),
|
||||
pathDecryptionNonce: Sodium.bin2base64(encryptedPath.nonce)),
|
||||
null,
|
||||
null,
|
||||
));
|
||||
return collection;
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ class FavoritesService {
|
|||
CollectionType.favorites,
|
||||
CollectionAttributes(),
|
||||
null,
|
||||
null,
|
||||
));
|
||||
_cachedFavoritesCollectionID = collection.id;
|
||||
return collection.id;
|
||||
|
|
|
@ -11,8 +11,9 @@ import 'gallery_app_bar_widget.dart';
|
|||
|
||||
class CollectionPage extends StatefulWidget {
|
||||
final Collection collection;
|
||||
final String tagPrefix;
|
||||
|
||||
const CollectionPage(this.collection, {Key key}) : super(key: key);
|
||||
const CollectionPage(this.collection, {this.tagPrefix = "collection", Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_CollectionPageState createState() => _CollectionPageState();
|
||||
|
@ -34,7 +35,7 @@ class _CollectionPageState extends State<CollectionPage> {
|
|||
reloadEvent: Bus.instance
|
||||
.on<CollectionUpdatedEvent>()
|
||||
.where((event) => event.collectionID == widget.collection.id),
|
||||
tagPrefix: "collection",
|
||||
tagPrefix: widget.tagPrefix,
|
||||
selectedFiles: _selectedFiles,
|
||||
);
|
||||
return Scaffold(
|
||||
|
|
|
@ -19,7 +19,7 @@ import 'package:photos/utils/toast_util.dart';
|
|||
|
||||
class SharingDialog extends StatefulWidget {
|
||||
final Collection collection;
|
||||
final List<String> sharees;
|
||||
final List<User> sharees;
|
||||
|
||||
SharingDialog(this.collection, this.sharees, {Key key}) : super(key: key);
|
||||
|
||||
|
@ -29,7 +29,7 @@ class SharingDialog extends StatefulWidget {
|
|||
|
||||
class _SharingDialogState extends State<SharingDialog> {
|
||||
bool _showEntryField = false;
|
||||
List<String> _sharees;
|
||||
List<User> _sharees;
|
||||
String _email;
|
||||
|
||||
@override
|
||||
|
@ -42,8 +42,8 @@ class _SharingDialogState extends State<SharingDialog> {
|
|||
Collection.typeToString(widget.collection.type) +
|
||||
"."));
|
||||
} else {
|
||||
for (final email in _sharees) {
|
||||
children.add(EmailItemWidget(widget.collection.id, email));
|
||||
for (final user in _sharees) {
|
||||
children.add(EmailItemWidget(widget.collection.id, user.email));
|
||||
}
|
||||
}
|
||||
if (_showEntryField) {
|
||||
|
@ -186,7 +186,7 @@ class _SharingDialogState extends State<SharingDialog> {
|
|||
await dialog.hide();
|
||||
showToast("Shared successfully!");
|
||||
setState(() {
|
||||
_sharees.add(email);
|
||||
_sharees.add(User(email: email));
|
||||
_showEntryField = false;
|
||||
});
|
||||
} catch (e) {
|
||||
|
|
|
@ -8,7 +8,10 @@ import 'package:photos/core/event_bus.dart';
|
|||
import 'package:photos/db/collections_db.dart';
|
||||
import 'package:photos/db/files_db.dart';
|
||||
import 'package:photos/events/collection_updated_event.dart';
|
||||
import 'package:photos/models/collection.dart';
|
||||
import 'package:photos/models/collection_items.dart';
|
||||
import 'package:photos/ui/collection_page.dart';
|
||||
import 'package:photos/ui/collections_gallery_widget.dart';
|
||||
import 'package:photos/ui/common_elements.dart';
|
||||
import 'package:photos/ui/loading_widget.dart';
|
||||
import 'package:photos/ui/shared_collection_page.dart';
|
||||
|
@ -36,40 +39,42 @@ class _SharedCollectionGalleryState extends State<SharedCollectionGallery> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder<List<CollectionWithThumbnail>>(
|
||||
return FutureBuilder<SharedCollections>(
|
||||
future:
|
||||
CollectionsDB.instance.getAllCollections().then((collections) async {
|
||||
final c = List<CollectionWithThumbnail>();
|
||||
final outgoing = List<CollectionWithThumbnail>();
|
||||
final incoming = List<CollectionWithThumbnail>();
|
||||
for (final collection in collections) {
|
||||
if (collection.owner.id == Configuration.instance.getUserID()) {
|
||||
continue;
|
||||
if (collection.sharees.length > 0) {
|
||||
final withThumbnail =
|
||||
await _getCollectionWithThumbnail(collection);
|
||||
if (withThumbnail.thumbnail != null) {
|
||||
outgoing.add(withThumbnail);
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
final withThumbnail = await _getCollectionWithThumbnail(collection);
|
||||
if (withThumbnail.thumbnail != null) {
|
||||
incoming.add(withThumbnail);
|
||||
}
|
||||
}
|
||||
final thumbnail =
|
||||
await FilesDB.instance.getLatestFileInCollection(collection.id);
|
||||
if (thumbnail == null) {
|
||||
continue;
|
||||
}
|
||||
final lastUpdatedFile = await FilesDB.instance
|
||||
.getLastModifiedFileInCollection(collection.id);
|
||||
c.add(CollectionWithThumbnail(
|
||||
collection,
|
||||
thumbnail,
|
||||
lastUpdatedFile,
|
||||
));
|
||||
}
|
||||
c.sort((first, second) {
|
||||
outgoing.sort((first, second) {
|
||||
return second.lastUpdatedFile.updationTime
|
||||
.compareTo(first.lastUpdatedFile.updationTime);
|
||||
});
|
||||
return c;
|
||||
incoming.sort((first, second) {
|
||||
return second.lastUpdatedFile.updationTime
|
||||
.compareTo(first.lastUpdatedFile.updationTime);
|
||||
});
|
||||
return SharedCollections(outgoing, incoming);
|
||||
}),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
if (snapshot.data.isEmpty) {
|
||||
return nothingToSeeHere;
|
||||
} else {
|
||||
return _getSharedCollectionsGallery(snapshot.data);
|
||||
}
|
||||
return _getSharedCollectionsGallery(snapshot.data);
|
||||
} else if (snapshot.hasError) {
|
||||
_logger.shout(snapshot.error);
|
||||
return Center(child: Text(snapshot.error.toString()));
|
||||
|
@ -80,26 +85,114 @@ class _SharedCollectionGalleryState extends State<SharedCollectionGallery> {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _getSharedCollectionsGallery(
|
||||
List<CollectionWithThumbnail> collections) {
|
||||
return Container(
|
||||
margin: EdgeInsets.only(top: 24),
|
||||
child: GridView.builder(
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.only(bottom: 12),
|
||||
physics: ScrollPhysics(), // to disable GridView's scrolling
|
||||
itemBuilder: (context, index) {
|
||||
return _buildCollection(context, collections[index]);
|
||||
},
|
||||
itemCount: collections.length,
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
),
|
||||
Widget _getSharedCollectionsGallery(SharedCollections collections) {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
SectionTitle("INCOMING"),
|
||||
Padding(padding: EdgeInsets.all(8)),
|
||||
collections.incoming.length > 0
|
||||
? GridView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
return _buildIncomingCollection(
|
||||
context, collections.incoming[index]);
|
||||
},
|
||||
itemCount: collections.incoming.length,
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
),
|
||||
)
|
||||
: nothingToSeeHere,
|
||||
Padding(padding: EdgeInsets.all(8)),
|
||||
Divider(height: 16),
|
||||
SectionTitle("OUTGOING"),
|
||||
Padding(padding: EdgeInsets.all(8)),
|
||||
collections.outgoing.length > 0
|
||||
? ListView.builder(
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.only(bottom: 12),
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
return _buildOutgoingCollection(
|
||||
context, collections.outgoing[index]);
|
||||
},
|
||||
itemCount: collections.outgoing.length,
|
||||
)
|
||||
: nothingToSeeHere,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCollection(BuildContext context, CollectionWithThumbnail c) {
|
||||
Widget _buildOutgoingCollection(
|
||||
BuildContext context, CollectionWithThumbnail c) {
|
||||
return GestureDetector(
|
||||
child: Container(
|
||||
margin: EdgeInsets.fromLTRB(16, 4, 8, 12),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(2.0),
|
||||
child: Container(
|
||||
child: Hero(
|
||||
tag: "outgoing_collection" + c.thumbnail.tag(),
|
||||
child: ThumbnailWidget(
|
||||
c.thumbnail,
|
||||
)),
|
||||
height: 60,
|
||||
width: 60,
|
||||
),
|
||||
),
|
||||
Padding(padding: EdgeInsets.all(8)),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
c.collection.name,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(0, 4, 0, 0),
|
||||
child: Text(
|
||||
"Shared with " +
|
||||
c.collection.sharees
|
||||
.map((u) => u.name.split(" ")[0])
|
||||
.join(", "),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryColorLight,
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
final page = CollectionPage(
|
||||
c.collection,
|
||||
tagPrefix: "outgoing_collection",
|
||||
);
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return page;
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildIncomingCollection(
|
||||
BuildContext context, CollectionWithThumbnail c) {
|
||||
return GestureDetector(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
|
@ -156,6 +249,19 @@ class _SharedCollectionGalleryState extends State<SharedCollectionGallery> {
|
|||
);
|
||||
}
|
||||
|
||||
Future<CollectionWithThumbnail> _getCollectionWithThumbnail(
|
||||
Collection collection) async {
|
||||
final thumbnail =
|
||||
await FilesDB.instance.getLatestFileInCollection(collection.id);
|
||||
final lastUpdatedFile =
|
||||
await FilesDB.instance.getLastModifiedFileInCollection(collection.id);
|
||||
return CollectionWithThumbnail(
|
||||
collection,
|
||||
thumbnail,
|
||||
lastUpdatedFile,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_subscription.cancel();
|
||||
|
|
Loading…
Add table
Reference in a new issue