Skip to content

Commit

Permalink
add share with circles ui for all profile details but name #2, #12, #13
Browse files Browse the repository at this point in the history
  • Loading branch information
LGro committed May 11, 2024
1 parent d9211eb commit 0177966
Show file tree
Hide file tree
Showing 6 changed files with 614 additions and 140 deletions.
3 changes: 3 additions & 0 deletions architectural_decision_records/sharing_profile_details.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Sharing Profile Details

In the context of enabling fine grained control over which contact sees which part of one's profile, facing the concern that with strong system contact schema integration, only with consistent index and label value a contact detail can be tracked for changes and otherwise needs to be reassigned sharing preferences from scratch we decided for only allowing the assignment between contact details and circles to achieve an easy maintainability in case of profile changes / additions, accepting that the shared profile can not be managed fine grained for any contact individually.
146 changes: 146 additions & 0 deletions lib/data/models/profile_sharing_settings.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Copyright 2024 The Coagulate Authors. All rights reserved.
// SPDX-License-Identifier: MPL-2.0

import 'package:equatable/equatable.dart';
// import 'package:json_annotation/json_annotation.dart';
// part 'profile_sharing_settings.g.dart';

/// Lists of circle IDs that have access to the corresponding name fields
// @JsonSerializable()
class NameSharingSettings extends Equatable {
const NameSharingSettings({
this.first = const [],
this.last = const [],
this.middle = const [],
this.prefix = const [],
this.suffix = const [],
this.nickname = const [],
this.firstPhonetic = const [],
this.lastPhonetic = const [],
this.middlePhonetic = const [],
});

final List<String> first;
final List<String> last;
final List<String> middle;
final List<String> prefix;
final List<String> suffix;
final List<String> nickname;
final List<String> firstPhonetic;
final List<String> lastPhonetic;
final List<String> middlePhonetic;

NameSharingSettings copyWith(
List<String>? first,
List<String>? last,
List<String>? middle,
List<String>? prefix,
List<String>? suffix,
List<String>? nickname,
List<String>? firstPhonetic,
List<String>? lastPhonetic,
List<String>? middlePhonetic,
) =>
NameSharingSettings(
first: first ?? this.first,
last: last ?? this.last,
middle: middle ?? this.middle,
prefix: prefix ?? this.prefix,
suffix: suffix ?? this.suffix,
nickname: nickname ?? this.nickname,
firstPhonetic: firstPhonetic ?? this.firstPhonetic,
lastPhonetic: lastPhonetic ?? this.lastPhonetic,
middlePhonetic: middlePhonetic ?? this.middlePhonetic,
);

@override
List<Object?> get props => [
first,
last,
middle,
prefix,
suffix,
nickname,
firstPhonetic,
lastPhonetic,
middlePhonetic,
];
}

// @JsonSerializable()
class ProfileSharingSettings extends Equatable {
const ProfileSharingSettings({
this.displayName = const [],
this.name = const NameSharingSettings(),
this.phones = const {},
this.emails = const {},
this.addresses = const {},
this.organizations = const {},
this.websites = const {},
this.socialMedias = const {},
this.events = const {},
});

/// List of circle IDs that have access to the displayName
final List<String> displayName;

/// Settings for which of the name fields are shared with which circle
final NameSharingSettings name;

/// Map of index|label to circle IDs that have access to phones
final Map<String, List<String>> phones;

/// Map of index|label to circle IDs that have access to emails
final Map<String, List<String>> emails;

/// Map of index|label to circle IDs that have access to addresses
final Map<String, List<String>> addresses;

/// Map of index|label to circle IDs that have access to organizations
final Map<String, List<String>> organizations;

/// Map of index|label to circle IDs that have access to websites
final Map<String, List<String>> websites;

/// Map of index|label to circle IDs that have access to socialMedias
final Map<String, List<String>> socialMedias;

/// Map of index|label to circle IDs that have access to events
final Map<String, List<String>> events;

ProfileSharingSettings copyWith({
List<String>? displayName,
NameSharingSettings? name,
Map<String, List<String>>? phones,
Map<String, List<String>>? emails,
Map<String, List<String>>? addresses,
Map<String, List<String>>? organizations,
Map<String, List<String>>? websites,
Map<String, List<String>>? socialMedias,
Map<String, List<String>>? events,
}) =>
ProfileSharingSettings(
displayName: displayName ?? this.displayName,
name: name ?? this.name,
phones: phones ?? this.phones,
emails: emails ?? this.emails,
addresses: addresses ?? this.addresses,
organizations: organizations ?? this.organizations,
websites: websites ?? this.websites,
socialMedias: socialMedias ?? this.socialMedias,
events: events ?? this.events,
);

@override
List<Object?> get props => [
displayName,
name,
phones,
emails,
addresses,
organizations,
websites,
socialMedias,
events,
];
}
6 changes: 6 additions & 0 deletions lib/data/repositories/contacts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import 'package:veilid/veilid.dart';
import '../../veilid_processor/repository/processor_repository.dart';
import '../models/coag_contact.dart';
import '../models/contact_update.dart';
import '../models/profile_sharing_settings.dart';
import '../providers/distributed_storage/base.dart';
import '../providers/persistent_storage/base.dart';
import '../providers/system_contacts/base.dart';
Expand Down Expand Up @@ -70,6 +71,11 @@ class ContactsRepository {
late final Timer? timerDhtRefresh;
String? profileContactId;

// TODO: Persistent storage and initialization
Map<String, String> circles = {'C1': 'Friends', 'C2': 'Neighbors'};
ProfileSharingSettings profileSharingSettings =
const ProfileSharingSettings();

Map<String, CoagContact> _contacts = {};
final _contactsStreamController = BehaviorSubject<CoagContact>();

Expand Down
2 changes: 1 addition & 1 deletion lib/ui/contact_details/page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Widget _qrCodeButton(BuildContext context,
]),
onPressed: () async {
print(qrCodeData);
showDialog<void>(
await showDialog<void>(
context: context,
builder: (_) => AlertDialog(
title: Text(alertTitle),
Expand Down
74 changes: 74 additions & 0 deletions lib/ui/profile/cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:json_annotation/json_annotation.dart';

import '../../data/models/coag_contact.dart';
import '../../data/models/contact_location.dart';
import '../../data/models/profile_sharing_settings.dart';
import '../../data/repositories/contacts.dart';

part 'cubit.g.dart';
Expand Down Expand Up @@ -111,6 +112,79 @@ class ProfileCubit extends Cubit<ProfileState> {
emit(state.copyWith(profileContact: updatedContact));
}

void updatePhoneSharingCircles(
int index, String label, List<String> circles) {
// TODO: Trigger a cleanup of the available label/index combinations somewhere, doesn't need to be here
final phones = Map<String, List<String>>.from(
contactsRepository.profileSharingSettings.phones);
phones['$index|$label'] = circles;
contactsRepository.profileSharingSettings =
contactsRepository.profileSharingSettings.copyWith(phones: phones);
}

void updateEmailSharingCircles(
int index, String label, List<String> circles) {
// TODO: Trigger a cleanup of the available label/index combinations somewhere, doesn't need to be here
final emails = Map<String, List<String>>.from(
contactsRepository.profileSharingSettings.emails);
emails['$index|$label'] = circles;
contactsRepository.profileSharingSettings =
contactsRepository.profileSharingSettings.copyWith(emails: emails);
}

void updateAddressSharingCircles(
int index, String label, List<String> circles) {
// TODO: Trigger a cleanup of the available label/index combinations somewhere, doesn't need to be here
final addresses = Map<String, List<String>>.from(
contactsRepository.profileSharingSettings.addresses);
addresses['$index|$label'] = circles;
contactsRepository.profileSharingSettings = contactsRepository
.profileSharingSettings
.copyWith(addresses: addresses);
}

void updateOrganizationSharingCircles(
int index, String label, List<String> circles) {
// TODO: Trigger a cleanup of the available label/index combinations somewhere, doesn't need to be here
final organizations = Map<String, List<String>>.from(
contactsRepository.profileSharingSettings.organizations);
organizations['$index|$label'] = circles;
contactsRepository.profileSharingSettings = contactsRepository
.profileSharingSettings
.copyWith(organizations: organizations);
}

void updateWebsiteSharingCircles(
int index, String label, List<String> circles) {
// TODO: Trigger a cleanup of the available label/index combinations somewhere, doesn't need to be here
final websites = Map<String, List<String>>.from(
contactsRepository.profileSharingSettings.websites);
websites['$index|$label'] = circles;
contactsRepository.profileSharingSettings =
contactsRepository.profileSharingSettings.copyWith(websites: websites);
}

void updateSocialMediaSharingCircles(
int index, String label, List<String> circles) {
// TODO: Trigger a cleanup of the available label/index combinations somewhere, doesn't need to be here
final socialMedias = Map<String, List<String>>.from(
contactsRepository.profileSharingSettings.socialMedias);
socialMedias['$index|$label'] = circles;
contactsRepository.profileSharingSettings = contactsRepository
.profileSharingSettings
.copyWith(socialMedias: socialMedias);
}

void updateEventSharingCircles(
int index, String label, List<String> circles) {
// TODO: Trigger a cleanup of the available label/index combinations somewhere, doesn't need to be here
final events = Map<String, List<String>>.from(
contactsRepository.profileSharingSettings.events);
events['$index|$label'] = circles;
contactsRepository.profileSharingSettings =
contactsRepository.profileSharingSettings.copyWith(events: events);
}

@override
Future<void> close() {
_contactsSubscription.cancel();
Expand Down
Loading

0 comments on commit 0177966

Please sign in to comment.