mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 11:08:06 +00:00
Change account photo
This commit is contained in:
parent
7d394f5313
commit
9421135fac
9 changed files with 182 additions and 37 deletions
|
|
@ -40,6 +40,7 @@ struct CallView: View {
|
|||
@ObservedObject var contactViewModel: ContactViewModel
|
||||
@ObservedObject var editContactViewModel: EditContactViewModel
|
||||
@ObservedObject var meetingViewModel: MeetingViewModel
|
||||
@ObservedObject var accountProfileViewModel: AccountProfileViewModel
|
||||
|
||||
@State private var addParticipantsViewModel: AddParticipantsViewModel?
|
||||
|
||||
|
|
@ -211,6 +212,7 @@ struct CallView: View {
|
|||
contactViewModel: contactViewModel,
|
||||
editContactViewModel: editContactViewModel,
|
||||
meetingViewModel: meetingViewModel,
|
||||
accountProfileViewModel: accountProfileViewModel,
|
||||
isShowConversationFragment: $isShowConversationFragment,
|
||||
isShowStartCallGroupPopup: $isShowStartCallGroupPopup,
|
||||
isShowEditContactFragment: $isShowEditContactFragment,
|
||||
|
|
@ -2842,6 +2844,7 @@ struct PressedButtonStyle: ButtonStyle {
|
|||
contactViewModel: ContactViewModel(),
|
||||
editContactViewModel: EditContactViewModel(),
|
||||
meetingViewModel: MeetingViewModel(),
|
||||
accountProfileViewModel: AccountProfileViewModel(),
|
||||
fullscreenVideo: .constant(false),
|
||||
isShowStartCallFragment: .constant(false),
|
||||
isShowConversationFragment: .constant(false),
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@ struct ContentView: View {
|
|||
@State var isShowScheduleMeetingFragment = false
|
||||
@State private var isShowLoginFragment: Bool = false
|
||||
|
||||
private let avatarSize = 45.0
|
||||
|
||||
var body: some View {
|
||||
let pub = NotificationCenter.default
|
||||
.publisher(for: NSNotification.Name("ContactLoaded"))
|
||||
|
|
@ -307,13 +309,31 @@ struct ContentView: View {
|
|||
VStack(spacing: 0) {
|
||||
if searchIsActive == false {
|
||||
HStack {
|
||||
Image("profile-image-example")
|
||||
.resizable()
|
||||
.frame(width: 45, height: 45)
|
||||
.clipShape(Circle())
|
||||
.onTapGesture {
|
||||
openMenu()
|
||||
AsyncImage(url: accountProfileViewModel.getImagePath()) { image in
|
||||
switch image {
|
||||
case .empty:
|
||||
ProgressView()
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
case .success(let image):
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
.clipShape(Circle())
|
||||
case .failure:
|
||||
Image(uiImage: contactsManager.textToImage(
|
||||
firstName: accountProfileViewModel.avatarModel?.name ?? "",
|
||||
lastName: ""))
|
||||
.resizable()
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
.clipShape(Circle())
|
||||
@unknown default:
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
.onTapGesture {
|
||||
openMenu()
|
||||
}
|
||||
|
||||
Text(String(localized: index == 0 ? "bottom_navigation_contacts_label" : (index == 1 ? "bottom_navigation_calls_label" : (index == 2 ? "bottom_navigation_conversations_label" : "bottom_navigation_meetings_label"))))
|
||||
.default_text_style_white_800(styleSize: 20)
|
||||
|
|
@ -867,6 +887,7 @@ struct ContentView: View {
|
|||
contactViewModel: contactViewModel,
|
||||
editContactViewModel: editContactViewModel,
|
||||
meetingViewModel: meetingViewModel,
|
||||
accountProfileViewModel: accountProfileViewModel,
|
||||
isShowConversationFragment: $isShowConversationFragment,
|
||||
isShowStartCallGroupPopup: $isShowStartCallGroupPopup,
|
||||
isShowEditContactFragment: $isShowEditContactFragment,
|
||||
|
|
@ -909,6 +930,7 @@ struct ContentView: View {
|
|||
}
|
||||
|
||||
SideMenu(
|
||||
accountProfileViewModel: accountProfileViewModel,
|
||||
width: geometry.size.width / 5 * 4,
|
||||
isOpen: self.sideMenuIsOpen,
|
||||
menuClose: self.openMenu,
|
||||
|
|
@ -1253,6 +1275,7 @@ struct ContentView: View {
|
|||
contactViewModel: contactViewModel,
|
||||
editContactViewModel: editContactViewModel,
|
||||
meetingViewModel: meetingViewModel,
|
||||
accountProfileViewModel: accountProfileViewModel,
|
||||
fullscreenVideo: $fullscreenVideo,
|
||||
isShowStartCallFragment: $isShowStartCallFragment,
|
||||
isShowConversationFragment: $isShowConversationFragment,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ struct ConversationFragment: View {
|
|||
@ObservedObject var contactViewModel: ContactViewModel
|
||||
@ObservedObject var editContactViewModel: EditContactViewModel
|
||||
@ObservedObject var meetingViewModel: MeetingViewModel
|
||||
@ObservedObject var accountProfileViewModel: AccountProfileViewModel
|
||||
|
||||
@State var isMenuOpen = false
|
||||
@State private var isMuted: Bool = false
|
||||
|
|
@ -995,6 +996,7 @@ struct ConversationFragment: View {
|
|||
contactViewModel: contactViewModel,
|
||||
editContactViewModel: editContactViewModel,
|
||||
meetingViewModel: meetingViewModel,
|
||||
accountProfileViewModel: accountProfileViewModel,
|
||||
isMuted: $isMuted,
|
||||
isShowEphemeralFragment: $isShowEphemeralFragment,
|
||||
isShowStartCallGroupPopup: $isShowStartCallGroupPopup,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ struct ConversationInfoFragment: View {
|
|||
@ObservedObject var contactViewModel: ContactViewModel
|
||||
@ObservedObject var editContactViewModel: EditContactViewModel
|
||||
@ObservedObject var meetingViewModel: MeetingViewModel
|
||||
@ObservedObject var accountProfileViewModel: AccountProfileViewModel
|
||||
|
||||
@State var addParticipantsViewModel = AddParticipantsViewModel()
|
||||
|
||||
|
|
@ -287,7 +288,33 @@ struct ConversationInfoFragment: View {
|
|||
VStack(spacing: 0) {
|
||||
ForEach(conversationViewModel.participantConversationModel) { participantConversationModel in
|
||||
HStack {
|
||||
Avatar(contactAvatarModel: participantConversationModel, avatarSize: 50)
|
||||
if conversationViewModel.myParticipantConversationModel != nil && conversationViewModel.myParticipantConversationModel!.address != participantConversationModel.address {
|
||||
Avatar(contactAvatarModel: participantConversationModel, avatarSize: 50)
|
||||
} else {
|
||||
let avatarSize = 50.0
|
||||
AsyncImage(url: accountProfileViewModel.getImagePath()) { image in
|
||||
switch image {
|
||||
case .empty:
|
||||
ProgressView()
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
case .success(let image):
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
.clipShape(Circle())
|
||||
case .failure:
|
||||
Image(uiImage: contactsManager.textToImage(
|
||||
firstName: accountProfileViewModel.avatarModel?.name ?? "",
|
||||
lastName: ""))
|
||||
.resizable()
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
.clipShape(Circle())
|
||||
@unknown default:
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VStack {
|
||||
Text(participantConversationModel.name)
|
||||
|
|
@ -667,6 +694,7 @@ struct ConversationInfoFragment: View {
|
|||
contactViewModel: ContactViewModel(),
|
||||
editContactViewModel: EditContactViewModel(),
|
||||
meetingViewModel: MeetingViewModel(),
|
||||
accountProfileViewModel: AccountProfileViewModel(),
|
||||
addParticipantsViewModel: AddParticipantsViewModel(),
|
||||
isMuted: .constant(false),
|
||||
isShowEphemeralFragment: .constant(false),
|
||||
|
|
|
|||
|
|
@ -469,17 +469,19 @@ class ConversationViewModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
if let currentUser = self.displayedConversation?.chatRoom.me,
|
||||
let address = currentUser.address {
|
||||
ContactAvatarModel.getAvatarModelFromAddress(address: address) { avatarResult in
|
||||
let avatarModelTmp = avatarResult
|
||||
DispatchQueue.main.async {
|
||||
if currentUser.isAdmin {
|
||||
self.isUserAdmin = true
|
||||
self.participantConversationModelAdmin.append(avatarModelTmp)
|
||||
if !self.displayedConversation!.isReadOnly {
|
||||
if let currentUser = self.displayedConversation?.chatRoom.me,
|
||||
let address = currentUser.address {
|
||||
ContactAvatarModel.getAvatarModelFromAddress(address: address) { avatarResult in
|
||||
let avatarModelTmp = avatarResult
|
||||
DispatchQueue.main.async {
|
||||
if currentUser.isAdmin {
|
||||
self.isUserAdmin = true
|
||||
self.participantConversationModelAdmin.append(avatarModelTmp)
|
||||
}
|
||||
self.participantConversationModel.append(avatarModelTmp)
|
||||
self.myParticipantConversationModel = avatarModelTmp
|
||||
}
|
||||
self.participantConversationModel.append(avatarModelTmp)
|
||||
self.myParticipantConversationModel = avatarModelTmp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import UniformTypeIdentifiers
|
|||
|
||||
struct SideMenu: View {
|
||||
|
||||
@ObservedObject var accountProfileViewModel: AccountProfileViewModel
|
||||
|
||||
let width: CGFloat
|
||||
let isOpen: Bool
|
||||
let menuClose: () -> Void
|
||||
|
|
@ -67,7 +69,7 @@ struct SideMenu: View {
|
|||
|
||||
List {
|
||||
ForEach(0..<CoreContext.shared.accounts.count, id: \.self) { index in
|
||||
SideMenuAccountRow( model: CoreContext.shared.accounts[index], isShowAccountProfileFragment: $isShowAccountProfileFragment)
|
||||
SideMenuAccountRow( model: CoreContext.shared.accounts[index], accountProfileViewModel: accountProfileViewModel, isShowAccountProfileFragment: $isShowAccountProfileFragment)
|
||||
.background()
|
||||
.listRowInsets(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16))
|
||||
.listRowSeparator(.hidden)
|
||||
|
|
@ -171,6 +173,7 @@ struct SideMenu: View {
|
|||
GeometryReader { geometry in
|
||||
@State var triggerNavigateToLogin: Bool = false
|
||||
SideMenu(
|
||||
accountProfileViewModel: AccountProfileViewModel(),
|
||||
width: geometry.size.width / 5 * 4,
|
||||
isOpen: true,
|
||||
menuClose: {},
|
||||
|
|
|
|||
|
|
@ -22,19 +22,40 @@ import linphonesw
|
|||
import UniformTypeIdentifiers
|
||||
|
||||
struct SideMenuAccountRow: View {
|
||||
@ObservedObject var contactsManager = ContactsManager.shared
|
||||
|
||||
@ObservedObject var model: AccountModel
|
||||
@ObservedObject var accountProfileViewModel: AccountProfileViewModel
|
||||
|
||||
@State private var navigateToOption = false
|
||||
@Binding var isShowAccountProfileFragment: Bool
|
||||
|
||||
private let avatarSize = 45.0
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Avatar(contactAvatarModel:
|
||||
ContactAvatarModel(friend: nil,
|
||||
name: model.displayName,
|
||||
address: model.address,
|
||||
withPresence: true),
|
||||
avatarSize: 45)
|
||||
AsyncImage(url: accountProfileViewModel.getImagePath()) { image in
|
||||
switch image {
|
||||
case .empty:
|
||||
ProgressView()
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
case .success(let image):
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
.clipShape(Circle())
|
||||
case .failure:
|
||||
Image(uiImage: contactsManager.textToImage(
|
||||
firstName: accountProfileViewModel.avatarModel?.name ?? "",
|
||||
lastName: ""))
|
||||
.resizable()
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
.clipShape(Circle())
|
||||
@unknown default:
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
.padding(.leading, 6)
|
||||
|
||||
VStack {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ struct AccountProfileFragment: View {
|
|||
@State private var selectedImage: UIImage?
|
||||
@State private var removedImage = false
|
||||
|
||||
private let avatarSize = 100.0
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geometry in
|
||||
VStack(spacing: 1) {
|
||||
|
|
@ -72,8 +74,6 @@ struct AccountProfileFragment: View {
|
|||
.padding(.bottom, 4)
|
||||
.background(.white)
|
||||
|
||||
Spacer()
|
||||
/*
|
||||
ScrollView {
|
||||
VStack(spacing: 0) {
|
||||
VStack(spacing: 0) {
|
||||
|
|
@ -87,22 +87,43 @@ struct AccountProfileFragment: View {
|
|||
VStack(spacing: 0) {
|
||||
if accountProfileViewModel.avatarModel != nil
|
||||
&& accountProfileViewModel.photoAvatarModel != nil
|
||||
&& !accountProfileViewModel.photoAvatarModel!.isEmpty && selectedImage == nil && !removedImage {
|
||||
Avatar(
|
||||
contactAvatarModel: ContactAvatarModel(accountProfileViewModel.avatarModel!),
|
||||
avatarSize: 100
|
||||
)
|
||||
&& !accountProfileViewModel.photoAvatarModel!.isEmpty
|
||||
&& selectedImage == nil && !removedImage {
|
||||
|
||||
AsyncImage(url: accountProfileViewModel.getImagePath()) { image in
|
||||
switch image {
|
||||
case .empty:
|
||||
ProgressView()
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
case .success(let image):
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
.clipShape(Circle())
|
||||
case .failure:
|
||||
Image(uiImage: contactsManager.textToImage(
|
||||
firstName: accountProfileViewModel.avatarModel?.name ?? "",
|
||||
lastName: ""))
|
||||
.resizable()
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
.clipShape(Circle())
|
||||
@unknown default:
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
} else if selectedImage == nil {
|
||||
Image("profil-picture-default")
|
||||
.resizable()
|
||||
.frame(width: 100, height: 100)
|
||||
.clipShape(Circle())
|
||||
Image(uiImage: contactsManager.textToImage(
|
||||
firstName: accountProfileViewModel.avatarModel?.name ?? "",
|
||||
lastName: ""))
|
||||
.resizable()
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
.clipShape(Circle())
|
||||
} else {
|
||||
Image(uiImage: selectedImage!)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: 100, height: 100)
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
.clipShape(Circle())
|
||||
}
|
||||
|
||||
|
|
@ -140,6 +161,7 @@ struct AccountProfileFragment: View {
|
|||
if let first = images.first {
|
||||
selectedImage = first
|
||||
removedImage = false
|
||||
saveImage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -150,6 +172,7 @@ struct AccountProfileFragment: View {
|
|||
Button(action: {
|
||||
removedImage = true
|
||||
selectedImage = nil
|
||||
saveImage()
|
||||
}, label: {
|
||||
HStack {
|
||||
Image("trash-simple")
|
||||
|
|
@ -192,6 +215,8 @@ struct AccountProfileFragment: View {
|
|||
if let first = images.first {
|
||||
selectedImage = first
|
||||
removedImage = false
|
||||
showPhotoPicker = false
|
||||
saveImage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -248,11 +273,19 @@ struct AccountProfileFragment: View {
|
|||
.padding(.top, 2)
|
||||
}
|
||||
.background(Color.gray100)
|
||||
*/
|
||||
}
|
||||
.background(Color.gray100)
|
||||
}
|
||||
.navigationTitle("")
|
||||
.navigationBarHidden(true)
|
||||
}
|
||||
|
||||
func saveImage() {
|
||||
accountProfileViewModel.saveImage(
|
||||
image: selectedImage
|
||||
?? ContactsManager.shared.textToImage(
|
||||
firstName: accountProfileViewModel.avatarModel!.name, lastName: ""),
|
||||
name: accountProfileViewModel.avatarModel!.name,
|
||||
prefix: ((selectedImage == nil) ? "-default" : ""))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import linphonesw
|
|||
|
||||
class AccountProfileViewModel: ObservableObject {
|
||||
|
||||
let photoAvatarModelKey = "photo_avatar_model"
|
||||
|
||||
@Published var avatarModel: ContactAvatarModel?
|
||||
@Published var photoAvatarModel: String?
|
||||
|
||||
|
|
@ -31,10 +33,38 @@ class AccountProfileViewModel: ObservableObject {
|
|||
if core.defaultAccount != nil {
|
||||
let displayNameTmp = core.defaultAccount!.displayName()
|
||||
let contactAddressTmp = core.defaultAccount!.contactAddress?.asStringUriOnly() ?? ""
|
||||
var photoAvatarModelTmp = ""
|
||||
|
||||
let preferences = UserDefaults.standard
|
||||
|
||||
if preferences.object(forKey: self.photoAvatarModelKey) == nil {
|
||||
preferences.set(self.photoAvatarModel ?? "", forKey: self.photoAvatarModelKey)
|
||||
} else {
|
||||
photoAvatarModelTmp = preferences.string(forKey: self.photoAvatarModelKey)!
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.avatarModel = ContactAvatarModel(friend: nil, name: displayNameTmp, address: contactAddressTmp, withPresence: false)
|
||||
self.photoAvatarModel = photoAvatarModelTmp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func saveImage(image: UIImage, name: String, prefix: String) {
|
||||
guard let data = image.jpegData(compressionQuality: 1) ?? image.pngData() else {
|
||||
return
|
||||
}
|
||||
|
||||
ContactsManager.shared.awaitDataWrite(data: data, name: name, prefix: prefix) { _, result in
|
||||
UserDefaults.standard.set(result, forKey: self.photoAvatarModelKey)
|
||||
self.photoAvatarModel = result
|
||||
}
|
||||
}
|
||||
|
||||
func getImagePath() -> URL {
|
||||
let imagePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent(self.photoAvatarModel ?? "Error")
|
||||
|
||||
return imagePath
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue