-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* 🚧 Add `MailRowItem`, `MailSheetView` * ✨ Implement `MailSheetView` for email sending feature - Implemented `MailSheetView` to present a modal view for sending emails upon button press * ✨ Implement email sending functionality with fallback - Implemented the functionality to send emails directly from the app. If unable to send an email, added code to redirect users to the Mail app store page * ♿ Improve accessibility features - Updated the app to hide images from Accessibility tools to avoid unnecessary distractions. - Added descriptive text for version information * ✨ Implement `DeviceProvider` protocol for dynamic mail body content - Created DeviceProvider protocol to abstract device-related information for use in composing email bodies. - Modified MailView to rely on DeviceProvider for dynamically populating the mail body with relevant device information, enhancing the detail and relevance of email communications. * ✅ Add DeviceInformationProvider tests
- Loading branch information
Showing
9 changed files
with
370 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
PyeonHaeng-iOS/Sources/Scenes/SettingsScene/Mail/DeviceProvider.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// | ||
// DeviceProvider.swift | ||
// PyeonHaeng-iOS | ||
// | ||
// Created by 홍승현 on 3/10/24. | ||
// | ||
|
||
import UIKit | ||
|
||
// MARK: - DeviceInformationProvider | ||
|
||
protocol DeviceInformationProvider { | ||
var deviceModel: String { get } | ||
var deviceOS: String { get } | ||
var appVersion: String { get } | ||
} | ||
|
||
// MARK: - SystemDeviceProvider | ||
|
||
struct SystemDeviceProvider: DeviceInformationProvider { | ||
var deviceModel: String { | ||
deviceIdentifier() | ||
} | ||
|
||
var deviceOS: String { | ||
UIDevice.current.systemVersion | ||
} | ||
|
||
var appVersion: String { | ||
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "Unknown" | ||
} | ||
|
||
/// 기종을 가져오는 함수 | ||
private func deviceIdentifier() -> String { | ||
var systemInfo = utsname() | ||
uname(&systemInfo) | ||
let machineMirror = Mirror(reflecting: systemInfo.machine) | ||
let identifier = machineMirror.children.reduce("") { identifier, element in | ||
guard let value = element.value as? Int8, value != 0 else { return identifier } | ||
return identifier + String(UnicodeScalar(UInt8(value))) | ||
} | ||
return identifier | ||
} | ||
} |
119 changes: 119 additions & 0 deletions
119
PyeonHaeng-iOS/Sources/Scenes/SettingsScene/Mail/MailRowItem.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// | ||
// MailRowItem.swift | ||
// PyeonHaeng-iOS | ||
// | ||
// Created by 홍승현 on 3/10/24. | ||
// | ||
|
||
import DesignSystem | ||
import MessageUI | ||
import SwiftUI | ||
|
||
// MARK: - MailRowItem | ||
|
||
struct MailRowItem: View { | ||
@State private var isMailPresented: Bool = false | ||
@State private var showAlert: Bool = false | ||
@Environment(\.openURL) var openURL | ||
|
||
private let deviceProvider: DeviceInformationProvider | ||
|
||
// MARK: Initializations | ||
|
||
init(deviceProvider: DeviceInformationProvider) { | ||
self.deviceProvider = deviceProvider | ||
} | ||
|
||
// MARK: Body | ||
|
||
var body: some View { | ||
Button(action: attemptToSendMail) { | ||
HStack { | ||
Image.notePencil | ||
.renderingMode(.template) | ||
.foregroundStyle(.gray900) | ||
Text("Contact Us") | ||
.font(.b1) | ||
Spacer() | ||
Image(systemName: Constants.disclosureImageName) | ||
.font(.system(size: Metrics.disclosureSize, weight: .semibold)) // Styled to look like a disclosure indicator | ||
.foregroundStyle(.gray.opacity(Metrics.disclosureOpacity)) | ||
} | ||
} | ||
.sheet(isPresented: $isMailPresented) { | ||
MailSheetView( | ||
subject: Constants.emailSubject, | ||
recipients: [Constants.emailAddress], | ||
messageBody: generateDefaultMessageBody() | ||
) | ||
} | ||
.alert(isPresented: $showAlert) { | ||
Alert( | ||
title: Text(Constants.alertTitle), | ||
message: Text(Constants.alertDescription), | ||
primaryButton: .default(Text(Constants.openAppStoreButtonText), action: moveToMailApp), | ||
secondaryButton: .cancel(Text(Constants.closeButtonText)) | ||
) | ||
} | ||
} | ||
|
||
// MARK: Private methods | ||
|
||
/// Attempts to present the mail view or shows an alert if mail cannot be sent. | ||
private func attemptToSendMail() { | ||
if MFMailComposeViewController.canSendMail() { | ||
isMailPresented = true | ||
} else { | ||
showAlert = true | ||
} | ||
} | ||
|
||
/// Opens the Mail app's page in the App Store. | ||
private func moveToMailApp() { | ||
if let url = URL(string: Constants.emailURL) { | ||
openURL(url) | ||
} | ||
} | ||
|
||
/// mail default contents | ||
private func generateDefaultMessageBody() -> String { | ||
""" | ||
Please write your message here. | ||
------------------- | ||
Device Model : \(deviceProvider.deviceModel) | ||
Device OS : \(deviceProvider.deviceOS) | ||
App Version : \(deviceProvider.appVersion) | ||
------------------- | ||
""" | ||
} | ||
} | ||
|
||
// MARK: - Metrics | ||
|
||
private enum Metrics { | ||
static let disclosureSize: CGFloat = 14 | ||
static let disclosureOpacity: CGFloat = 0.5 | ||
} | ||
|
||
// MARK: - Constants | ||
|
||
private enum Constants { | ||
static let alertTitle: LocalizedStringKey = "Cannot Send Mail" | ||
static let alertDescription: LocalizedStringKey = """ | ||
Your device is not configured to send mail. | ||
Would you like to install a mail app from the App Store? | ||
""" | ||
|
||
static let disclosureImageName: String = "chevron.right" | ||
|
||
static let openAppStoreButtonText: LocalizedStringKey = "Open App Store" | ||
static let closeButtonText: LocalizedStringKey = "Close" | ||
|
||
/// Represents the URL to the Mail app in the App Store. | ||
static let emailURL: String = "https://apps.apple.com/app/mail/id1108187098" | ||
static let emailSubject: String = "<편행> 문의하기" | ||
static let emailAddress: String = "[email protected]" | ||
} |
Oops, something went wrong.