Commit 11cd8da4 authored by zhangzhe's avatar zhangzhe

新增录音

parent dae5e19a
......@@ -138,6 +138,8 @@
CC29A709251C71AC0059BD5C /* SHSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC29A708251C71AC0059BD5C /* SHSwift.swift */; };
CC29A716251C75210059BD5C /* SHInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC29A715251C75210059BD5C /* SHInputView.swift */; };
CC29A71B251C790D0059BD5C /* SHInputBottomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC29A71A251C790D0059BD5C /* SHInputBottomView.swift */; };
CCAD0B782521C97F00781276 /* SHInputAudioPlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCAD0B772521C97F00781276 /* SHInputAudioPlayView.swift */; };
CCAD0B7D2521D5C600781276 /* SHInputProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCAD0B7C2521D5C600781276 /* SHInputProgressView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
......@@ -338,6 +340,8 @@
CC29A708251C71AC0059BD5C /* SHSwift.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SHSwift.swift; sourceTree = "<group>"; };
CC29A715251C75210059BD5C /* SHInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SHInputView.swift; sourceTree = "<group>"; };
CC29A71A251C790D0059BD5C /* SHInputBottomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SHInputBottomView.swift; sourceTree = "<group>"; };
CCAD0B772521C97F00781276 /* SHInputAudioPlayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SHInputAudioPlayView.swift; sourceTree = "<group>"; };
CCAD0B7C2521D5C600781276 /* SHInputProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SHInputProgressView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -831,6 +835,8 @@
CC13DB73251C9A2F00835654 /* SHInputTextView.swift */,
CC29A71A251C790D0059BD5C /* SHInputBottomView.swift */,
CC13DB78251CA62800835654 /* SHInputAudioButton.swift */,
CCAD0B7C2521D5C600781276 /* SHInputProgressView.swift */,
CCAD0B772521C97F00781276 /* SHInputAudioPlayView.swift */,
);
path = View;
sourceTree = "<group>";
......@@ -1110,6 +1116,7 @@
A95CE00A24E0F42F0066DAE6 /* CRDateFormatter.swift in Sources */,
A95CDFC024E0EBF10066DAE6 /* Date+Extension.swift in Sources */,
A924A84B251B842C00CB2947 /* SHRecordDetailsBottomView.swift in Sources */,
CCAD0B782521C97F00781276 /* SHInputAudioPlayView.swift in Sources */,
A94EE118251B682C0066B490 /* SHSettingViewController.swift in Sources */,
A95CDFC424E0EBF10066DAE6 /* Double+Extension.swift in Sources */,
CC13DB6A251C83E600835654 /* SHInputViewModel.swift in Sources */,
......@@ -1136,6 +1143,7 @@
A950F5AF24F4E06E007AB63E /* SHMineViewController.swift in Sources */,
A95CE02F24E151340066DAE6 /* UIButton+Category.m in Sources */,
A94D935924F7969600A886C0 /* CMNetworkManager.swift in Sources */,
CCAD0B7D2521D5C600781276 /* SHInputProgressView.swift in Sources */,
A94DD56724FDF29700B1B5A2 /* XBAudioUnitPlayer.m in Sources */,
A94DD56F24FDF29700B1B5A2 /* XBAACEncoder_system.m in Sources */,
A95CE03624E1729B0066DAE6 /* SHRecordWaveView.swift in Sources */,
......@@ -1330,8 +1338,8 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "ShorthandMaster/速记大师.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 8F4PP38DC3;
......@@ -1350,7 +1358,7 @@
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = com.ShorthandMaster.www;
PRODUCT_NAME = "速记大师";
PROVISIONING_PROFILE_SPECIFIER = "";
PROVISIONING_PROFILE_SPECIFIER = ShorthandMasterDevProfile;
SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/ShorthandMaster/ShorthandMaster-Bridging-Header.h";
SWIFT_OBJC_INTERFACE_HEADER_NAME = "ShorthandMaster-Swift.h";
SWIFT_VERSION = 5.0;
......@@ -1364,8 +1372,8 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "ShorthandMaster/速记大师.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 8F4PP38DC3;
......@@ -1384,7 +1392,7 @@
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = com.ShorthandMaster.www;
PRODUCT_NAME = "速记大师";
PROVISIONING_PROFILE_SPECIFIER = "";
PROVISIONING_PROFILE_SPECIFIER = ShorthandMasterDevProfile;
SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/ShorthandMaster/ShorthandMaster-Bridging-Header.h";
SWIFT_OBJC_INTERFACE_HEADER_NAME = "ShorthandMaster-Swift.h";
SWIFT_VERSION = 5.0;
......
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "input_audio_10before@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "input_audio_10before@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "input_audio_10later@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "input_audio_10later@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "input_audio_pause@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "input_audio_pause@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "input_audio_play@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "input_audio_play@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "input_copy@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "input_copy@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "input_share@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "input_share@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
//
// SHInputAudioPlayView.swift
// ShorthandMaster
//
// Created by 张哲 on 2020/9/28.
// Copyright © 2020 明津李. All rights reserved.
//
import UIKit
class SHInputAudioPlayView: UIView {
// MARK: - property
/// 播放/暂停按钮
var playButton: UIButton!
/// 时长
var timeLabel: UILabel!
/// 竖线
var line: UIView!
/// 播放速度按钮
var speedButton: UIButton!
// MARK - func
override init(frame: CGRect)
{
super.init(frame: frame)
self.backgroundColor = UIColor(r: 241, g: 241, b: 241)
self.layer.masksToBounds = true
self.layer.cornerRadius = 15
self.addSubviews()
self.setUpSubviewsLocation()
}
required init?(coder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
// MAKR: - UI
func addSubviews()
{
// 播放/暂停按钮
self.playButton = UIButton(type: .custom)
self.playButton.setImage(UIImage(named: "input_audio_play"), for: .normal)
self.addSubview(self.playButton)
// 时长
self.timeLabel = UILabel()
self.timeLabel.textColor = UIColor(r: 65, g: 131, b: 244)
self.timeLabel.font = UIFont(name: SHPingFangMedium, size: 14)
self.addSubview(self.timeLabel)
// 竖线
self.line = UIView()
self.line.backgroundColor = UIColor(r: 65, g: 131, b: 244)
self.addSubview(self.line)
// 播放速度按钮
self.speedButton = UIButton(type: .system)
self.speedButton.setTitle("x1.5", for: .normal)
self.speedButton.setTitleColor(UIColor(r: 65, g: 131, b: 244), for: .normal)
self.speedButton.titleLabel?.font = UIFont(name: SHPingFangMedium, size: 14)
self.addSubview(self.speedButton)
}
// MARK: 控件位置
func setUpSubviewsLocation()
{
self.playButton.mas_makeConstraints { (make) in
make?.left.mas_equalTo()(9)
make?.centerY.mas_equalTo()(self)
make?.size.mas_equalTo()(CGSize(width: 27, height: 30))
}
self.timeLabel.mas_makeConstraints { (make) in
make?.left.equalTo()(self.playButton.mas_right)
make?.centerY.equalTo()(self)
}
self.line.mas_makeConstraints { (make) in
make?.right.mas_equalTo()(-55)
make?.centerY.equalTo()(self)
make?.size.mas_equalTo()(CGSize(width: 1, height: 8))
}
self.speedButton.mas_makeConstraints { (make) in
make?.left.equalTo()(self.line.mas_right)
make?.right.mas_equalTo()(-9)
make?.top.bottom()?.mas_equalTo()(0)
}
}
}
//
// SHInputProgressView.swift
// ShorthandMaster
//
// Created by 张哲 on 2020/9/28.
// Copyright © 2020 明津李. All rights reserved.
//
import UIKit
class SHInputProgressView: UIView {
// MARK: - property
/// 后退10s按钮
var beforeButton: UIButton!
/// 前进10s按钮
var laterButton: UIButton!
/// 进度条
var slider: UISlider!
/// 播放时间
var timeLabel: UILabel!
// MARK - func
override init(frame: CGRect)
{
super.init(frame: frame)
self.addSubviews()
self.setUpSubviewsLocation()
}
required init?(coder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
// MAKR: - UI
func addSubviews()
{
// 后退10s按钮
self.beforeButton = UIButton(type: .custom)
self.beforeButton.setImage(UIImage(named: "input_audio_10before"), for: .normal)
self.addSubview(self.beforeButton)
// 前进10s按钮
self.laterButton = UIButton(type: .custom)
self.laterButton.setImage(UIImage(named: "input_audio_10later"), for: .normal)
self.addSubview(self.laterButton)
// 进度条
self.slider = UISlider()
self.slider.minimumTrackTintColor = UIColor(r: 102, g: 160, b: 255)
self.slider.maximumTrackTintColor = UIColor(r: 238, g: 238, b: 238)
self.addSubview(self.slider)
let thumView = UIView(frame: CGRect(x: 0, y: 0, width: 12, height: 12))
thumView.backgroundColor = UIColor(r: 102, g: 160, b: 255)
thumView.layer.masksToBounds = true
thumView.cornerRadius = 6
self.slider.setThumbImage(UIImage.imageWithView2(view: thumView), for: .normal)
self.slider.setThumbImage(UIImage.imageWithView2(view: thumView), for: .highlighted)
// 播放时间
self.timeLabel = UILabel()
self.timeLabel.text = "00:00:00"
self.timeLabel.textColor = UIColor(r: 102, g: 102, b: 102)
self.timeLabel.font = UIFont(name: SHPingFangRegular, size: 14)
self.addSubview(self.timeLabel)
}
// MARK: 控件位置
func setUpSubviewsLocation()
{
self.beforeButton.mas_makeConstraints { (make) in
make?.left.mas_equalTo()(20 - 8)
make?.centerY.mas_equalTo()(self)
make?.size.mas_equalTo()(CGSize(width: 24 + 8 * 2, height: 24 + 14 * 2))
}
self.laterButton.mas_makeConstraints { (make) in
make?.right.mas_equalTo()(8 - 20)
make?.centerY.mas_equalTo()(self)
make?.size.mas_equalTo()(CGSize(width: 24 + 8 * 2, height: 24 + 14 * 2))
}
self.slider.mas_makeConstraints { (make) in
make?.left.equalTo()(self.beforeButton.mas_right)
make?.right.equalTo()(self.timeLabel.mas_left)?.offset()(-8)
make?.centerY.mas_equalTo()(self)
make?.height.mas_equalTo()(24)
}
self.timeLabel.mas_makeConstraints { (make) in
make?.right.equalTo()(self.laterButton.mas_left)?.offset()(-8)
make?.centerY.mas_equalTo()(self)
make?.width.mas_equalTo()(60)
}
}
}
......@@ -28,6 +28,13 @@ class SHInputTextView: UITextView {
{
delegateOK.textViewDidDelete?(textView: self)
}
}
}
extension SHInputTextView: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
}
}
......@@ -16,11 +16,16 @@ class SHInputView: UIView {
var bottomView : SHInputBottomView!
var isEdited: Bool = Bool()
// MARK: - func
override init(frame: CGRect)
init(frame: CGRect, isEdited: Bool)
{
super.init(frame: frame)
self.isEdited = isEdited
self.addSubviews()
self.setUpSubviewsLocation()
......@@ -32,6 +37,8 @@ class SHInputView: UIView {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(note:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
......@@ -45,6 +52,7 @@ class SHInputView: UIView {
self.textView.textColor = UIColor.init(r: 34, g: 34, b: 34, a: 1)
self.textView.font = UIFont.init(name: SHPingFangMedium, size: 18)
self.textView.contentInset = UIEdgeInsets.init(top: 24, left: 0, bottom: 0, right: 0);
self.textView.alwaysBounceVertical = true
self.addSubview(self.textView)
// 占位文字
......@@ -55,7 +63,7 @@ class SHInputView: UIView {
self.textView.addSubview(self.placeholder)
// 底部栏
self.bottomView = SHInputBottomView.init()
self.bottomView = SHInputBottomView.init(frame: .zero, isEdited: isEdited)
self.addSubview(self.bottomView)
}
......@@ -107,9 +115,7 @@ class SHInputView: UIView {
weakSelf?.bottomView.mas_updateConstraints { (make) in
make?.left.right()?.mas_equalTo()(0)
make?.bottom.mas_equalTo()(-height + SafeAreaBottomHeight())
make?.height.mas_equalTo()(50 + SafeAreaBottomHeight());
}
......@@ -131,8 +137,7 @@ class SHInputView: UIView {
weakSelf?.bottomView.mas_updateConstraints { (make) in
make?.left.right().bottom()?.mas_equalTo()(0)
make?.height.mas_equalTo()(50 + SafeAreaBottomHeight());
make?.bottom.mas_equalTo()(0)
}
......
......@@ -11,22 +11,11 @@ import UIKit
class SHInputViewModel: NSObject {
// MARK: - property
// /// 标题文字
// var title : String = ""
// /// 内容文字
// var content : String = ""
// /// 图片数组
// var imageArray : Array = Array<Any>()
// var recordModel : SHRecordModel = SHRecordModel()
// MARK: - func
// MARK: 标题文字样式
class func titleAttributes() -> NSDictionary
func titleAttributes() -> NSDictionary
{
let paragraphStyle : NSMutableParagraphStyle = NSMutableParagraphStyle.init()
paragraphStyle.lineSpacing = 5;
......@@ -40,7 +29,7 @@ class SHInputViewModel: NSObject {
}
// MARK: 内容文字样式
class func contentAttributes() -> NSDictionary
func contentAttributes() -> NSDictionary
{
let paragraphStyle : NSMutableParagraphStyle = NSMutableParagraphStyle.init()
paragraphStyle.lineSpacing = 5;
......@@ -52,30 +41,54 @@ class SHInputViewModel: NSObject {
return titleAttributes
}
// MARK: 沙盒文件夹路径, 生成沙盒文件, 图片和录音都保存在这个路径下
lazy var documentFilePath : String = {
let dateFormat = Date().format("yyyyMMdd")
let time = Date.init().timeStamp
let filePath = "/" + dateFormat + time
if !FileManager.default.fileExists(atPath: DocumentPath + filePath)
{
do
{
try FileManager.default.createDirectory(atPath: DocumentPath + filePath, withIntermediateDirectories: true, attributes: nil)
}
catch let error
{
print(error)
}
}
return filePath
}()
// MARK: 获取textView中的图片, 保存到本地, 并生成数组
class func setUpImageArrayWithTextView(textView: UITextView) -> (imagesPathArray: Array<String>, imagesIndexArray: Array<Int>)
func setUpImageArrayWithTextView(textView: UITextView) -> (imagesPathArray: Array<String>, imagesIndexArray: Array<Int>)
{
/// 图片路径数组
var imagesPathArray = Array<String>()
/// 图片位置数组
var imagesIndexArray = Array<Int>()
// 创建文件夹
/// 文件夹路径
let subFile = Date().format("yyyyMMdd")
let time = Date.init().timeStamp
let filePath = DocumentPath + "/" + subFile + time
do
{
try FileManager.default.createDirectory(atPath: filePath, withIntermediateDirectories: true, attributes: nil)
}
catch let error
{
print(error)
return (imagesPathArray, imagesIndexArray)
}
// // 创建文件夹
// /// 文件夹路径
// let dateFormat = Date().format("yyyyMMdd")
// let time = Date.init().timeStamp
// let filePath = DocumentPath + "/" + dateFormat + time
// do
// {
// try FileManager.default.createDirectory(atPath: filePath, withIntermediateDirectories: true, attributes: nil)
// }
// catch let error
// {
// print(error)
//
// return (imagesPathArray, imagesIndexArray)
// }
// 遍历textView文字中的NSTextAttachment
......@@ -96,7 +109,7 @@ class SHInputViewModel: NSObject {
let imageData : Data = (imageAttachment.image?.jpegData(compressionQuality: 1.0))!
// 保存的本地路径
let imagePath = "/" + subFile + time + "/" + "image.jpeg" + imagesPathArray.count.string
let imagePath = self.documentFilePath + "/image" + imagesPathArray.count.string + ".jpeg"
let imageUrl : URL = URL(fileURLWithPath: DocumentPath + imagePath)
......@@ -128,4 +141,62 @@ class SHInputViewModel: NSObject {
return (imagesPathArray, imagesIndexArray)
}
// MARK: 编辑状态下进入页面时, 把SHRecordModel类型数据转成NSMutableAttributedString
func getAttributedStringWithSHRecordModel(recordModel: SHRecordModel) -> NSAttributedString
{
let attributeString : NSMutableAttributedString = NSMutableAttributedString()
let titleString = NSAttributedString(string: recordModel.rename, attributes: (self.titleAttributes() as! [NSAttributedString.Key : Any]))
attributeString.append(titleString)
let contentString = NSAttributedString(string: recordModel.txt, attributes: self.contentAttributes() as? [NSAttributedString.Key : Any])
attributeString.append(contentString)
let imagesPath : Array = recordModel.imagesPath
let imagesIndex : Array = recordModel.imagesIndex
var i = 0
for imagePath : String in imagesPath
{
let image : UIImage = UIImage(contentsOfFile: DocumentPath + imagePath) ?? UIImage()
// 调整图片大小, 宽相同, 高随比例变化
let newWidth = kScreenWidth - 20 * 2
let newHeight = newWidth * image.size.height / image.size.width
let newSize = CGSize(width: newWidth, height: newHeight)
let imageLocation : Int = imagesIndex[i]
let attachment = NSTextAttachment.init()
attachment.image = image
attachment.bounds = CGRect(origin: CGPoint.zero, size: newSize)
let imageString = NSMutableAttributedString(attachment: attachment)
// 设置图片文字属性
imageString.addAttributes((self.contentAttributes() as? [NSAttributedString.Key : Any])!, range: NSRange(location: 0, length: imageString.length))
// 设置图片间距
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 18
imageString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: imageString.length))
attributeString.insert(imageString, at: imageLocation)
i += 1
}
return attributeString
}
// MARK: 秒数转00:00:00格式
func getTimeStringWithSeconds(seconds : NSInteger) -> String
{
let hour = seconds / 60 / 60
let minute = (seconds - hour * 60 * 60) / 60
let second = seconds - hour * 60 * 60 - minute * 60
return String(format: "%02d:%02d:%02d", hour, minute, second)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment