Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Sign in / Register
Toggle navigation
J
jami-client-ios
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Insights
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Locked Files
Issues
27
Issues
27
List
Boards
Labels
Milestones
Security & Compliance
Security & Compliance
Dependency List
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
savoirfairelinux
jami-client-ios
Commits
0eb233d5
Commit
0eb233d5
authored
Mar 29, 2019
by
Kateryna Kostiuk
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
video: hardware decoding/encoding
Change-Id: Ia86d0a42802438cc9eaba15b768eee4f4a01a941
parent
caf0e652
Changes
25
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
685 additions
and
68 deletions
+685
-68
Ring/Ring.xcodeproj/project.pbxproj
Ring/Ring.xcodeproj/project.pbxproj
+40
-3
Ring/Ring.xcodeproj/xcshareddata/xcschemes/libring.xcscheme
Ring/Ring.xcodeproj/xcshareddata/xcschemes/libring.xcscheme
+87
-0
Ring/Ring/AppDelegate.swift
Ring/Ring/AppDelegate.swift
+28
-2
Ring/Ring/Bridging/Utils.h
Ring/Ring/Bridging/Utils.h
+3
-0
Ring/Ring/Bridging/Utils.mm
Ring/Ring/Bridging/Utils.mm
+25
-0
Ring/Ring/Bridging/VideoAdapter.h
Ring/Ring/Bridging/VideoAdapter.h
+5
-0
Ring/Ring/Bridging/VideoAdapter.mm
Ring/Ring/Bridging/VideoAdapter.mm
+46
-3
Ring/Ring/Constants/Generated/Images.swift
Ring/Ring/Constants/Generated/Images.swift
+1
-0
Ring/Ring/Constants/Generated/Strings.swift
Ring/Ring/Constants/Generated/Strings.swift
+7
-0
Ring/Ring/Contact/ContactViewModel.swift
Ring/Ring/Contact/ContactViewModel.swift
+1
-1
Ring/Ring/Features/Conversations/ConversationsCoordinator.swift
...ing/Features/Conversations/ConversationsCoordinator.swift
+7
-0
Ring/Ring/Features/Conversations/SmartList/SmartlistViewController.storyboard
...onversations/SmartList/SmartlistViewController.storyboard
+60
-19
Ring/Ring/Features/Conversations/SmartList/SmartlistViewController.swift
...res/Conversations/SmartList/SmartlistViewController.swift
+38
-36
Ring/Ring/Features/Conversations/SmartList/SmartlistViewModel.swift
...Features/Conversations/SmartList/SmartlistViewModel.swift
+4
-0
Ring/Ring/GeneralSettings/GeneralSettingsViewController.storyboard
.../GeneralSettings/GeneralSettingsViewController.storyboard
+80
-0
Ring/Ring/GeneralSettings/GeneralSettingsViewController.swift
.../Ring/GeneralSettings/GeneralSettingsViewController.swift
+108
-0
Ring/Ring/GeneralSettings/GeneralSettingsViewModel.swift
Ring/Ring/GeneralSettings/GeneralSettingsViewModel.swift
+86
-0
Ring/Ring/Protocols/ConversationNavigation.swift
Ring/Ring/Protocols/ConversationNavigation.swift
+1
-0
Ring/Ring/Resources/Images.xcassets/settings.imageset/Contents.json
...Resources/Images.xcassets/settings.imageset/Contents.json
+26
-0
Ring/Ring/Resources/Images.xcassets/settings.imageset/icons8-settings-1.png
...s/Images.xcassets/settings.imageset/icons8-settings-1.png
+0
-0
Ring/Ring/Resources/Images.xcassets/settings.imageset/icons8-settings-2.png
...s/Images.xcassets/settings.imageset/icons8-settings-2.png
+0
-0
Ring/Ring/Resources/Images.xcassets/settings.imageset/icons8-settings.png
...ces/Images.xcassets/settings.imageset/icons8-settings.png
+0
-0
Ring/Ring/Resources/en.lproj/Localizable.strings
Ring/Ring/Resources/en.lproj/Localizable.strings
+4
-0
Ring/Ring/Resources/encoder.json
Ring/Ring/Resources/encoder.json
+6
-0
Ring/Ring/Services/VideoService.swift
Ring/Ring/Services/VideoService.swift
+22
-4
No files found.
Ring/Ring.xcodeproj/project.pbxproj
View file @
0eb233d5
This diff is collapsed.
Click to expand it.
Ring/Ring.xcodeproj/xcshareddata/xcschemes/libring.xcscheme
0 → 100644
View file @
0eb233d5
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion =
"1010"
version =
"1.3"
>
<BuildAction
parallelizeBuildables =
"YES"
buildImplicitDependencies =
"YES"
>
<BuildActionEntries>
<BuildActionEntry
buildForTesting =
"YES"
buildForRunning =
"YES"
buildForProfiling =
"YES"
buildForArchiving =
"YES"
buildForAnalyzing =
"YES"
>
<BuildableReference
BuildableIdentifier =
"primary"
BlueprintIdentifier =
"62366028200914C1002598C1"
BuildableName =
"libring"
BlueprintName =
"libring"
ReferencedContainer =
"container:Ring.xcodeproj"
>
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration =
"Debug"
selectedDebuggerIdentifier =
"Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier =
"Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv =
"YES"
>
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration =
"Debug"
selectedDebuggerIdentifier =
"Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier =
"Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle =
"0"
useCustomWorkingDirectory =
"NO"
ignoresPersistentStateOnLaunch =
"NO"
debugDocumentVersioning =
"YES"
debugServiceExtension =
"internal"
allowLocationSimulation =
"YES"
>
<MacroExpansion>
<BuildableReference
BuildableIdentifier =
"primary"
BlueprintIdentifier =
"62366028200914C1002598C1"
BuildableName =
"libring"
BlueprintName =
"libring"
ReferencedContainer =
"container:Ring.xcodeproj"
>
</BuildableReference>
</MacroExpansion>
<EnvironmentVariables>
<EnvironmentVariable
key =
"AVLOGLEVEL"
value =
"40"
isEnabled =
"YES"
>
</EnvironmentVariable>
</EnvironmentVariables>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration =
"Release"
shouldUseLaunchSchemeArgsEnv =
"YES"
savedToolIdentifier =
""
useCustomWorkingDirectory =
"NO"
debugDocumentVersioning =
"YES"
>
<MacroExpansion>
<BuildableReference
BuildableIdentifier =
"primary"
BlueprintIdentifier =
"62366028200914C1002598C1"
BuildableName =
"libring"
BlueprintName =
"libring"
ReferencedContainer =
"container:Ring.xcodeproj"
>
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration =
"Debug"
>
</AnalyzeAction>
<ArchiveAction
buildConfiguration =
"Release"
revealArchiveInOrganizer =
"YES"
>
</ArchiveAction>
</Scheme>
Ring/Ring/AppDelegate.swift
View file @
0eb233d5
...
...
@@ -117,8 +117,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
// sets output device to whatever is currently available (either spk / headset)
self
.
audioService
.
startAVAudioSession
()
// disables hardware decoding
self
.
videoService
.
setDecodingAccelerated
(
withState
:
false
)
prepareVideoAcceleration
()
// requests permission to use the camera
// will enumerate and add devices once permission has been granted
...
...
@@ -161,6 +160,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
}
guard
let
currentAccount
=
self
.
accountService
.
currentAccount
else
{
self
.
log
.
error
(
"Can't get current account!"
)
//if we don't have any account means it is first run, so enable hardware acceleration
self
.
videoService
.
setDecodingAccelerated
(
withState
:
true
)
self
.
videoService
.
setEncodingAccelerated
(
withState
:
true
)
UserDefaults
.
standard
.
set
(
true
,
forKey
:
hardareAccelerationKey
)
return
}
self
.
reloadDataFor
(
account
:
currentAccount
)
...
...
@@ -219,6 +222,29 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
self
.
clearBadgeNumber
()
}
func
prepareVideoAcceleration
()
{
// we want enable hardware acceleration by default so if key does not exists,
// means it was not disabled by user
let
keyExists
=
UserDefaults
.
standard
.
object
(
forKey
:
hardareAccelerationKey
)
!=
nil
let
enable
=
keyExists
?
UserDefaults
.
standard
.
bool
(
forKey
:
hardareAccelerationKey
)
:
false
self
.
videoService
.
setDecodingAccelerated
(
withState
:
enable
)
self
.
videoService
.
setEncodingAccelerated
(
withState
:
enable
)
guard
let
codecInfoPath
=
Bundle
.
main
.
path
(
forResource
:
"encoder"
,
ofType
:
".json"
)
else
{
return
}
guard
let
destPath
=
NSSearchPathForDirectoriesInDomains
(
.
documentDirectory
,
.
userDomainMask
,
true
)
.
first
else
{
return
}
let
fileManager
=
FileManager
.
default
guard
let
fullDestPath
=
NSURL
(
fileURLWithPath
:
destPath
)
.
appendingPathComponent
(
"encoder.json"
)
else
{
return
}
let
fullDestPathString
=
fullDestPath
.
path
do
{
try
fileManager
.
copyItem
(
atPath
:
codecInfoPath
,
toPath
:
fullDestPathString
)
}
catch
{
}
}
// MARK: - Ring Daemon
fileprivate
func
startDaemon
()
{
...
...
Ring/Ring/Bridging/Utils.h
View file @
0eb233d5
...
...
@@ -24,6 +24,7 @@
#import <map>
#import <string>
#import <vector>
struct
AVFrame
;
@interface
Utils
:
NSObject
...
...
@@ -35,4 +36,6 @@
+
(
NSData
*
)
dataFromVectorOfUInt8
:(
std
::
vector
<
uint8_t
>
)
vectorOfUInt8
;
+
(
std
::
vector
<
uint8_t
>
)
vectorOfUInt8FromData
:(
NSData
*
)
data
;
+
(
std
::
vector
<
std
::
map
<
std
::
string
,
std
::
string
>>
)
arrayOfDictionnarisToVectorOfMap
:(
NSArray
*
)
dictionaries
;
+
(
UIImage
*
)
convertHardwareDecodedFrameToImage
:(
const
AVFrame
*
)
frame
;
+
(
AVFrame
*
)
configureHardwareDecodedFrame
:(
AVFrame
*
)
frame
fromImageBuffer
:
(
CVImageBufferRef
)
image
;
@end
Ring/Ring/Bridging/Utils.mm
View file @
0eb233d5
...
...
@@ -20,6 +20,9 @@
*/
#import "Utils.h"
extern "C" {
#include <libavutil/frame.h>
}
@implementation Utils
...
...
@@ -105,4 +108,26 @@
return vector;
}
+ (UIImage*)convertHardwareDecodedFrameToImage:(const AVFrame*)frame {
if ((CVPixelBufferRef)frame->data[3]) {
CIImage *image = [CIImage imageWithCVPixelBuffer: (CVPixelBufferRef)frame->data[3]];
UIImage * imageUI = [UIImage imageWithCIImage:image];
return imageUI;
}
return [[UIImage alloc] init];
}
+ (AVFrame*)configureHardwareDecodedFrame:(AVFrame*)frame fromImageBuffer:(CVImageBufferRef) image {
//get dimensions
CVPixelBufferLockBaseAddress(image,0);
size_t width = CVPixelBufferGetWidth(image);
size_t height = CVPixelBufferGetHeight(image);
CVPixelBufferUnlockBaseAddress(image,0);
frame->data[3] = (uint8_t *)image;
frame->format = AV_PIX_FMT_VIDEOTOOLBOX;
frame->width = static_cast<int>(width);
frame->height = static_cast<int>(height);
return frame;
}
@end
Ring/Ring/Bridging/VideoAdapter.h
View file @
0eb233d5
...
...
@@ -20,6 +20,7 @@
#import <Foundation/Foundation.h>
#import <AVFoundation/AVCaptureOutput.h>
#import <AVFoundation/AVFoundation.h>
@protocol
VideoAdapterDelegate
;
...
...
@@ -30,9 +31,13 @@
-
(
void
)
addVideoDeviceWithName
:(
NSString
*
)
deviceName
withDevInfo
:(
NSDictionary
*
)
deviceInfoDict
;
-
(
void
)
registerSinkTargetWithSinkId
:
sinkId
withWidth
:
(
NSInteger
)
w
withHeight
:
(
NSInteger
)
h
;
-
(
void
)
removeSinkTargetWithSinkId
:(
NSString
*
)
sinkId
;
-
(
void
)
writeOutgoingHardwareDecodedFrameWithBuffer
:(
CVImageBufferRef
)
image
;
-
(
void
)
writeOutgoingFrameWithImage
:(
UIImage
*
)
image
;
-
(
void
)
setDecodingAccelerated
:(
BOOL
)
state
;
-
(
BOOL
)
getDecodingAccelerated
;
-
(
void
)
switchInput
:(
NSString
*
)
deviceName
;
-
(
void
)
switchInput
:(
NSString
*
)
deviceName
forCall
:(
NSString
*
)
callID
;
-
(
void
)
setEncodingAccelerated
:(
BOOL
)
state
;
-
(
BOOL
)
getEncodingAccelerated
;
@end
Ring/Ring/Bridging/VideoAdapter.mm
View file @
0eb233d5
...
...
@@ -27,6 +27,7 @@
#include <functional>
#include <AVFoundation/AVFoundation.h>
#include <mutex>
#import "Utils.h"
using namespace DRing;
...
...
@@ -36,11 +37,26 @@ struct Renderer
std::condition_variable frameCv;
bool isRendering;
std::mutex renderMutex;
AVSinkTarget avtarget;
SinkTarget target;
SinkTarget::FrameBufferPtr daemonFramePtr_;
int width;
int height;
void bindAVSinkFunctions() {
avtarget.push = [this](std::unique_ptr<DRing::VideoFrame> frame) {
if(!VideoAdapter.delegate) {
return;
}
@autoreleasepool {
UIImage *image = [Utils
convertHardwareDecodedFrameToImage: std::move(frame->pointer())];
isRendering = true;
[VideoAdapter.delegate writeFrameWithImage: image];
isRendering = false;
}
};
}
void bindSinkFunctions() {
target.pull = [this](std::size_t bytes) {
std::lock_guard<std::mutex> lk(renderMutex);
...
...
@@ -146,8 +162,13 @@ static id <VideoAdapterDelegate> _delegate;
auto renderer = std::make_shared<Renderer>();
renderer->width = static_cast<int>(w);
renderer->height = static_cast<int>(h);
renderer->bindSinkFunctions();
DRing::registerSinkTarget(_sinkId, renderer->target);
if(self.getDecodingAccelerated) {
renderer->bindAVSinkFunctions();
DRing::registerAVSinkTarget(_sinkId, renderer->avtarget);
} else {
renderer->bindSinkFunctions();
DRing::registerSinkTarget(_sinkId, renderer->target);
}
renderers.insert(std::make_pair(_sinkId, renderer));
}
...
...
@@ -162,7 +183,17 @@ static id <VideoAdapterDelegate> _delegate;
}
}
- (void)writeOutgoingFrameWithImage:(UIImage*)image {
- (void)writeOutgoingHardwareDecodedFrameWithBuffer:(CVImageBufferRef)image {
auto frame = DRing::getNewFrame();
if(!frame) {
return;
}
auto avframe = frame->pointer();
[Utils configureHardwareDecodedFrame:(AVFrame*)avframe fromImageBuffer: image];
DRing::publishFrame();
}
- (void)writeOutgoingFrameWithImage:(UIImage *)image {
unsigned capacity = 4 * image.size.width * image.size.height;
uint8_t* buf = (uint8_t*)DRing::obtainFrame(capacity);
if (buf){
...
...
@@ -196,6 +227,18 @@ static id <VideoAdapterDelegate> _delegate;
DRing::setDecodingAccelerated(state);
}
- (BOOL)getDecodingAccelerated {
return DRing::getDecodingAccelerated();
}
- (void)setEncodingAccelerated:(BOOL)state {
DRing::setEncodingAccelerated(state);
}
- (BOOL)getEncodingAccelerated {
return DRing::getEncodingAccelerated();
}
- (void)switchInput:(NSString*)deviceName {
DRing::switchInput(std::string([deviceName UTF8String]));
}
...
...
Ring/Ring/Constants/Generated/Images.swift
View file @
0eb233d5
...
...
@@ -57,6 +57,7 @@ internal enum Asset {
internal
static
let
ringLogo
=
ImageAsset
(
name
:
"ring_logo"
)
internal
static
let
scan
=
ImageAsset
(
name
:
"scan"
)
internal
static
let
sendButton
=
ImageAsset
(
name
:
"send_button"
)
internal
static
let
settings
=
ImageAsset
(
name
:
"settings"
)
internal
static
let
settingsIcon
=
ImageAsset
(
name
:
"settings_icon"
)
internal
static
let
shareButton
=
ImageAsset
(
name
:
"share_button"
)
internal
static
let
stopCall
=
ImageAsset
(
name
:
"stop_call"
)
...
...
Ring/Ring/Constants/Generated/Strings.swift
View file @
0eb233d5
...
...
@@ -291,6 +291,13 @@ internal enum L10n {
internal
static
let
readableStatusSuccess
=
L10n
.
tr
(
"Localizable"
,
"dataTransfer.readableStatusSuccess"
)
}
internal
enum
GeneralSettings
{
/// General settings
internal
static
let
title
=
L10n
.
tr
(
"Localizable"
,
"generalSettings.title"
)
/// Enable video acceleration
internal
static
let
videoAcceleration
=
L10n
.
tr
(
"Localizable"
,
"generalSettings.videoAcceleration"
)
}
internal
enum
GeneratedMessage
{
/// Contact added
internal
static
let
contactAdded
=
L10n
.
tr
(
"Localizable"
,
"generatedMessage.contactAdded"
)
...
...
Ring/Ring/Contact/ContactViewModel.swift
View file @
0eb233d5
...
...
@@ -41,7 +41,7 @@ class ContactViewModel: ViewModel, Stateable {
private
let
accountService
:
AccountsService
private
let
conversationService
:
ConversationsService
private
let
nameService
:
NameService
lazy
var
tableSection
:
Observable
<
[
SectionModel
<
String
,
ContactActions
>
]
>
=
{
lazy
var
tableSection
:
Observable
<
[
SectionModel
<
String
,
ContactActions
>
]
>
=
{
let
jamiSettings
=
[
SectionModel
(
model
:
"ProfileInfoCell"
,
items
:
...
...
Ring/Ring/Features/Conversations/ConversationsCoordinator.swift
View file @
0eb233d5
...
...
@@ -57,6 +57,8 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, ConversationNa
self
.
createNewAccount
()
case
.
showDialpad
(
let
inCall
):
self
.
showDialpad
(
inCall
:
inCall
)
case
.
showGeneralSettings
:
self
.
showGeneralSettings
()
default
:
break
}
...
...
@@ -109,6 +111,11 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, ConversationNa
}
}
func
showGeneralSettings
()
{
let
settingsViewController
=
GeneralSettingsViewController
.
instantiate
(
with
:
self
.
injectionBag
)
self
.
present
(
viewController
:
settingsViewController
,
withStyle
:
.
present
,
withAnimation
:
true
,
disposeBag
:
self
.
disposeBag
)
}
func
puchConversation
(
participantId
:
String
)
{
let
conversationViewModel
=
ConversationViewModel
(
with
:
self
.
injectionBag
)
guard
let
account
=
accountService
.
currentAccount
else
{
...
...
Ring/Ring/Features/Conversations/SmartList/SmartlistViewController.storyboard
View file @
0eb233d5
This diff is collapsed.
Click to expand it.
Ring/Ring/Features/Conversations/SmartList/SmartlistViewController.swift
View file @
0eb233d5
...
...
@@ -55,6 +55,10 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
@IBOutlet
weak
var
settingsButton
:
UIButton
!
@IBOutlet
weak
var
dialpadButton
:
UIButton
!
@IBOutlet
weak
var
dialpadButtonShadow
:
UIView
!
@IBOutlet
weak
var
searchBarShadow
:
UIView
!
@IBOutlet
weak
var
qrScanButton
:
UIButton
!
@IBOutlet
weak
var
phoneBookButton
:
UIButton
!
@IBOutlet
weak
var
scanButtonLeadingConstraint
:
NSLayoutConstraint
!
// account selection
var
accounPicker
=
UIPickerView
()
...
...
@@ -151,21 +155,22 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
}
})
.
disposed
(
by
:
self
.
disposeBag
)
let
imageScanSearch
=
UIImage
(
asset
:
Asset
.
qrCodeScan
)
as
UIImage
?
let
scanButton
=
UIButton
(
type
:
UIButtonType
.
custom
)
as
UIButton
scanButton
.
setImage
(
imageScanSearch
,
for
:
.
normal
)
let
scanButtonItem
=
UIBarButtonItem
(
customView
:
scanButton
)
scanButton
.
rx
.
tap
.
throttle
(
0.5
,
scheduler
:
MainScheduler
.
instance
)
let
imageSettings
=
UIImage
(
asset
:
Asset
.
settings
)
as
UIImage
?
let
generalSettingsButton
=
UIButton
(
type
:
UIButtonType
.
system
)
as
UIButton
generalSettingsButton
.
setImage
(
imageSettings
,
for
:
.
normal
)
generalSettingsButton
.
contentMode
=
.
scaleAspectFill
let
settingsButtonItem
=
UIBarButtonItem
(
customView
:
generalSettingsButton
)
generalSettingsButton
.
rx
.
tap
.
throttle
(
0.5
,
scheduler
:
MainScheduler
.
instance
)
.
subscribe
(
onNext
:
{
[
unowned
self
]
in
self
.
viewModel
.
showGeneralSettings
()
})
.
disposed
(
by
:
self
.
disposeBag
)
qrScanButton
.
rx
.
tap
.
throttle
(
0.5
,
scheduler
:
MainScheduler
.
instance
)
.
subscribe
(
onNext
:
{
[
unowned
self
]
in
self
.
openScan
()
})
.
disposed
(
by
:
self
.
disposeBag
)
let
imageOpenPhoneContacts
=
UIImage
(
asset
:
Asset
.
phoneBook
)
as
UIImage
?
let
phoneBookButton
=
UIButton
(
type
:
UIButtonType
.
custom
)
as
UIButton
phoneBookButton
.
setImage
(
imageOpenPhoneContacts
,
for
:
.
normal
)
phoneBookButton
.
contentMode
=
.
scaleAspectFill
let
contactsButtonItem
=
UIBarButtonItem
(
customView
:
phoneBookButton
)
phoneBookButton
.
rx
.
tap
.
throttle
(
0.5
,
scheduler
:
MainScheduler
.
instance
)
.
subscribe
(
onNext
:
{
[
unowned
self
]
in
self
.
contactPicker
.
delegate
=
self
...
...
@@ -178,15 +183,23 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
if
let
account
=
currentAccount
{
let
accountSip
=
account
.
type
==
AccountType
.
sip
self
.
navigationItem
.
rightBarButtonItem
=
accountSip
?
contactsButtonItem
:
scan
ButtonItem
.
rightBarButtonItem
=
accountSip
?
nil
:
settings
ButtonItem
self
.
dialpadButtonShadow
.
isHidden
=
!
accountSip
self
.
phoneBookButton
.
isHidden
=
!
accountSip
self
.
qrScanButton
.
isHidden
=
accountSip
}
})
.
disposed
(
by
:
disposeBag
)
self
.
navigationItem
.
rightBarButtonItem
=
scanButtonItem
if
let
account
=
self
.
viewModel
.
currentAccount
,
account
.
type
==
AccountType
.
sip
{
self
.
navigationItem
.
rightBarButtonItem
=
contactsButtonItem
self
.
navigationItem
.
rightBarButtonItem
=
settingsButtonItem
if
let
account
=
self
.
viewModel
.
currentAccount
{
if
account
.
type
==
AccountType
.
sip
{
self
.
navigationItem
.
rightBarButtonItem
=
nil
self
.
qrScanButton
.
isHidden
=
true
self
.
phoneBookButton
.
isHidden
=
false
}
else
{
self
.
qrScanButton
.
isHidden
=
false
self
.
phoneBookButton
.
isHidden
=
true
}
}
//create accounts button
...
...
@@ -388,13 +401,13 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
self
.
searchBar
.
tintColor
=
UIColor
.
jamiMain
self
.
searchBar
.
barTintColor
=
UIColor
.
jamiNavigationBar
self
.
view
.
bringSubview
(
toFront
:
self
.
searchBar
)
self
.
view
.
bringSubview
(
toFront
:
self
.
searchBar
Shadow
)
self
.
searchBar
.
layer
.
shadowColor
=
UIColor
.
black
.
cgColor
self
.
searchBar
.
layer
.
shadowOffset
=
CGSize
(
width
:
0.0
,
height
:
2.5
)
self
.
searchBar
.
layer
.
shadowOpacity
=
0.2
self
.
searchBar
.
layer
.
shadowRadius
=
3
self
.
searchBar
.
layer
.
masksToBounds
=
false
self
.
searchBar
Shadow
.
layer
.
shadowColor
=
UIColor
.
black
.
cgColor
self
.
searchBar
Shadow
.
layer
.
shadowOffset
=
CGSize
(
width
:
0.0
,
height
:
2.5
)
self
.
searchBar
Shadow
.
layer
.
shadowOpacity
=
0.2
self
.
searchBar
Shadow
.
layer
.
shadowRadius
=
3
self
.
searchBar
Shadow
.
layer
.
masksToBounds
=
false
//Bind the SearchBar to the ViewModel
self
.
searchBar
.
rx
.
text
.
orEmpty
...
...
@@ -404,12 +417,14 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
//Show Cancel button
self
.
searchBar
.
rx
.
textDidBeginEditing
.
subscribe
(
onNext
:
{
[
unowned
self
]
in
self
.
searchBar
.
setShowsCancelButton
(
true
,
animated
:
true
)
self
.
scanButtonLeadingConstraint
.
constant
=
-
40
self
.
searchBar
.
setShowsCancelButton
(
true
,
animated
:
false
)
})
.
disposed
(
by
:
disposeBag
)
//Hide Cancel button
self
.
searchBar
.
rx
.
textDidEndEditing
.
subscribe
(
onNext
:
{
[
unowned
self
]
in
self
.
searchBar
.
setShowsCancelButton
(
false
,
animated
:
true
)
self
.
scanButtonLeadingConstraint
.
constant
=
10
self
.
searchBar
.
setShowsCancelButton
(
false
,
animated
:
false
)
})
.
disposed
(
by
:
disposeBag
)
//Cancel button event
...
...
@@ -566,23 +581,10 @@ extension SmartlistViewController: CNContactPickerDelegate {
}
func
setNumberFromContact
(
contactNumber
:
String
)
{
//UPDATE YOUR NUMBER SELECTION LOGIC AND PERFORM ACTION WITH THE SELECTED NUMBER
var
contactNumber
=
contactNumber
.
replacingOccurrences
(
of
:
"-"
,
with
:
""
)
contactNumber
=
contactNumber
.
replacingOccurrences
(
of
:
"("
,
with
:
""
)
contactNumber
=
contactNumber
.
replacingOccurrences
(
of
:
")"
,
with
:
""
)
self
.
viewModel
.
showSipConversation
(
withNumber
:
contactNumber
)
// self.viewModel.searchBarText.value = contactNumber
//contactNumber = contactNumber.removeWhitespacesInBetween()
// guard contactNumber.count >= 10 else {
// dismiss(animated: true) {
// // self.popUpMessageError(value: 10, message: "Selected contact does not have a valid number")
// }
// return
// }
//textFieldNumber.text = String(contactNumber.suffix(10))
}
func
contactPickerDidCancel
(
_
picker
:
CNContactPickerViewController
)
{
...
...
Ring/Ring/Features/Conversations/SmartList/SmartlistViewModel.swift
View file @
0eb233d5
...
...
@@ -401,4 +401,8 @@ class SmartlistViewModel: Stateable, ViewModel {
func
showDialpad
()
{
self
.
stateSubject
.
onNext
(
ConversationState
.
showDialpad
(
inCall
:
false
))
}
func
showGeneralSettings
()
{
self
.
stateSubject
.
onNext
(
ConversationState
.
showGeneralSettings
())
}
}
Ring/Ring/GeneralSettings/GeneralSettingsViewController.storyboard
0 → 100644
View file @
0eb233d5
<?xml version="1.0" encoding="UTF-8"?>
<document
type=
"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB"
version=
"3.0"
toolsVersion=
"14460.31"
targetRuntime=
"iOS.CocoaTouch"
propertyAccessControl=
"none"
useAutolayout=
"YES"
useTraitCollections=
"YES"
useSafeAreas=
"YES"
colorMatched=
"YES"
initialViewController=
"0KF-lS-cXQ"
>
<device
id=
"retina4_7"
orientation=
"portrait"
>
<adaptation
id=
"fullscreen"
/>
</device>
<dependencies>
<deployment
identifier=
"iOS"
/>
<plugIn
identifier=
"com.apple.InterfaceBuilder.IBCocoaTouchPlugin"
version=
"14460.20"
/>
<capability
name=
"Safe area layout guides"
minToolsVersion=
"9.0"
/>
<capability
name=
"documents saved in the Xcode 8 format"
minToolsVersion=
"8.0"
/>
</dependencies>
<scenes>
<!--General Settings View Controller-->
<scene
sceneID=
"35j-2a-aAz"
>
<objects>
<viewController
hidesBottomBarWhenPushed=
"YES"
id=
"0KF-lS-cXQ"
customClass=
"GeneralSettingsViewController"
customModule=
"Ring"
customModuleProvider=
"target"
sceneMemberID=
"viewController"
>
<view
key=
"view"
contentMode=
"scaleToFill"
id=
"tdP-kF-vrw"
>
<rect
key=
"frame"
x=
"0.0"
y=
"0.0"
width=
"375"
height=
"667"
/>
<autoresizingMask
key=
"autoresizingMask"
widthSizable=
"YES"
heightSizable=
"YES"
/>
<subviews>
<view
contentMode=
"scaleToFill"
translatesAutoresizingMaskIntoConstraints=
"NO"
id=
"OaU-bt-R2w"
>
<rect
key=
"frame"
x=
"0.0"
y=
"0.0"
width=
"375"
height=
"120"
/>
<subviews>
<label
opaque=
"NO"
userInteractionEnabled=
"NO"
contentMode=
"left"
horizontalHuggingPriority=
"251"
verticalHuggingPriority=
"251"
text=
"General Settings"
textAlignment=
"natural"
lineBreakMode=
"tailTruncation"
baselineAdjustment=
"alignBaselines"
adjustsFontSizeToFit=
"NO"
translatesAutoresizingMaskIntoConstraints=
"NO"
id=
"fm1-VN-ppT"
>
<rect
key=
"frame"
x=
"80.5"
y=
"53.5"
width=
"214"
height=
"38.5"
/>
<fontDescription
key=
"fontDescription"
type=
"system"
weight=
"thin"
pointSize=
"32"
/>
<color
key=
"textColor"
red=
"0.1215686275"
green=
"0.28627450980000002"
blue=
"0.4431372549"
alpha=
"1"
colorSpace=
"custom"
customColorSpace=
"sRGB"
/>
<nil
key=
"highlightedColor"
/>
</label>
<button
opaque=
"NO"
contentMode=
"scaleToFill"
contentHorizontalAlignment=
"center"
contentVerticalAlignment=
"center"
buttonType=
"roundedRect"
lineBreakMode=
"middleTruncation"
translatesAutoresizingMaskIntoConstraints=
"NO"
id=
"NE7-nL-DvW"
>
<rect
key=
"frame"
x=
"14"
y=
"60"
width=
"25"
height=
"25"
/>
<constraints>
<constraint
firstAttribute=
"height"
constant=
"25"
id=
"R0J-pI-wkz"
/>
<constraint
firstAttribute=
"width"
constant=
"25"
id=
"gl1-ki-xOB"
/>
</constraints>
<color
key=
"tintColor"
red=
"0.1215686275"
green=
"0.28627450980000002"
blue=
"0.4431372549"
alpha=
"1"
colorSpace=
"custom"
customColorSpace=
"sRGB"
/>
<state
key=
"normal"
image=
"cross"
/>
</button>
</subviews>
<constraints>
<constraint
firstItem=
"fm1-VN-ppT"
firstAttribute=
"centerX"
secondItem=
"OaU-bt-R2w"
secondAttribute=
"centerX"
id=
"1kP-cu-cDP"
/>
<constraint
firstAttribute=
"bottom"
secondItem=
"NE7-nL-DvW"
secondAttribute=
"bottom"
constant=
"35"
id=
"Hsx-he-cDE"
/>
<constraint
firstAttribute=
"height"
constant=
"120"
id=
"JGl-fJ-5S9"
/>
<constraint
firstItem=
"fm1-VN-ppT"
firstAttribute=
"centerY"
secondItem=
"NE7-nL-DvW"
secondAttribute=
"centerY"
id=
"TAY-0E-oeR"
/>
<constraint
firstItem=
"NE7-nL-DvW"
firstAttribute=
"leading"
secondItem=
"OaU-bt-R2w"
secondAttribute=
"leading"
constant=
"14"
id=
"Ytg-WO-MP4"
/>
</constraints>
</view>
<tableView
clipsSubviews=
"YES"
contentMode=
"scaleToFill"
alwaysBounceVertical=
"YES"
dataMode=
"prototypes"
style=
"plain"
separatorStyle=
"default"
rowHeight=
"-1"
estimatedRowHeight=
"-1"
sectionHeaderHeight=
"28"
sectionFooterHeight=
"28"
translatesAutoresizingMaskIntoConstraints=
"NO"
id=
"XAa-ES-xki"
>
<rect
key=
"frame"
x=
"0.0"
y=
"120"
width=
"375"
height=
"547"
/>
<color
key=
"backgroundColor"
white=
"1"
alpha=
"1"
colorSpace=
"custom"
customColorSpace=
"genericGamma22GrayColorSpace"
/>
</tableView>
</subviews>
<color
key=
"backgroundColor"
white=
"1"
alpha=
"1"
colorSpace=
"custom"
customColorSpace=
"genericGamma22GrayColorSpace"
/>
<constraints>
<constraint
firstItem=
"OaU-bt-R2w"
firstAttribute=
"top"
secondItem=
"tdP-kF-vrw"
secondAttribute=
"top"
id=
"99o-PS-Hfy"
/>
<constraint
firstItem=
"OaU-bt-R2w"
firstAttribute=
"leading"
secondItem=
"tdP-kF-vrw"
secondAttribute=
"leading"
id=
"9Aq-IP-zrF"
/>
<constraint
firstItem=
"XAa-ES-xki"
firstAttribute=
"trailing"
secondItem=
"f8H-BQ-kNd"
secondAttribute=
"trailing"
id=
"Ekj-a6-3GP"
/>
<constraint
firstItem=
"XAa-ES-xki"
firstAttribute=
"bottom"
secondItem=
"f8H-BQ-kNd"
secondAttribute=
"bottom"
id=
"JGK-tS-24D"
/>
<constraint
firstItem=
"XAa-ES-xki"
firstAttribute=
"leading"
secondItem=
"f8H-BQ-kNd"
secondAttribute=
"leading"
id=
"Kob-5x-TQ2"
/>
<constraint
firstAttribute=
"trailing"
secondItem=
"OaU-bt-R2w"
secondAttribute=
"trailing"
id=
"Nht-yV-tfZ"
/>
<constraint
firstItem=
"XAa-ES-xki"
firstAttribute=
"top"
secondItem=
"OaU-bt-R2w"
secondAttribute=
"bottom"
id=
"dHt-YB-mRk"
/>
</constraints>
<viewLayoutGuide
key=
"safeArea"
id=
"f8H-BQ-kNd"
/>
</view>
<extendedEdge
key=
"edgesForExtendedLayout"
/>
<connections>
<outlet
property=
"doneButton"
destination=
"NE7-nL-DvW"
id=
"a2F-oe-Fon"
/>
<outlet
property=
"settingsTable"
destination=
"XAa-ES-xki"
id=
"Af8-lt-Nsn"
/>
<outlet
property=
"tilteLabel"
destination=
"fm1-VN-ppT"
id=
"ycX-1U-ihE"
/>
</connections>
</viewController>
<placeholder
placeholderIdentifier=
"IBFirstResponder"
id=
"1qI-Sw-ka9"
userLabel=
"First Responder"
sceneMemberID=
"firstResponder"
/>
</objects>
<point
key=
"canvasLocation"
x=
"-108"
y=
"137.18140929535232"
/>
</scene>
</scenes>
<resources>
<image
name=
"cross"
width=
"40"
height=
"40"
/>
</resources>
</document>
Ring/Ring/GeneralSettings/GeneralSettingsViewController.swift
0 → 100644
View file @
0eb233d5
/*
* Copyright (C) 2019 Savoir-faire Linux Inc.
*
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
import
Reusable
import
UIKit
import
RxSwift
import
RxCocoa
import
RxDataSources
class
GeneralSettingsViewController
:
UIViewController
,
StoryboardBased
,
ViewModelBased
{
var
viewModel
:
GeneralSettingsViewModel
!
let
disposeBag
=
DisposeBag
()
@IBOutlet
weak
var
doneButton
:
UIButton
!
@IBOutlet
weak
var
tilteLabel
:
UILabel
!
@IBOutlet
weak
var
settingsTable
:
UITableView
!
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
self
.
applyL10n
()
self
.
setUpTable
()
doneButton
.
rx
.
tap
.
subscribe
(
onNext
:
{
[
unowned
self
]
in
self
.
dismiss
(
animated
:
true
,
completion
:
nil
)
})
.
disposed
(
by
:
self
.
disposeBag
)
}
func
setUpTable
()
{
self
.
settingsTable
.
estimatedRowHeight
=
35
self
.
settingsTable
.
rowHeight
=
UITableViewAutomaticDimension
self
.
settingsTable
.
tableFooterView
=
UIView
()
self
.
setUpDataSource
()
}
func
applyL10n
()
{
tilteLabel
.
text
=
L10n
.
GeneralSettings
.
title
}
private
func
setUpDataSource
()
{
let
configureCell
:
(
TableViewSectionedDataSource
,
UITableView
,
IndexPath
,
GeneralSettingsSection
.
Item
)
->
UITableViewCell
=
{
(
dataSource
:
TableViewSectionedDataSource
<
GeneralSettingsSection
>
,
tableView
:
UITableView
,
indexPath
:
IndexPath
,
item
:
GeneralSettingsSection
.
Item
)
in
switch
dataSource
[
indexPath
]
{
case
.
hardwareAcceleration
:
let
cell
=
DisposableCell
()
//L10n.CreateProfile.title
//"generalSettings.title" = "General settings";
//"generalSettings.videoAcceleration" = "Enable video acceleration";
cell
.
textLabel
?
.
text
=
L10n
.
GeneralSettings
.
videoAcceleration
let
switchView
=
UISwitch
()
cell
.
selectionStyle
=
.
none
switchView
.
frame
=
CGRect
(
x
:
self
.
view
.
frame
.
size
.
width
-
63
,
y
:
cell
.
frame
.
size
.
height
*
0.5
-
15
,
width
:
49
,
height
:
30
)
cell
.
contentView
.
addSubview
(
switchView
)
switchView
.
setOn
(
self
.
viewModel
.
hardwareAccelerationEnabled
.
value
,
animated
:
false
)
self
.
viewModel
.
hardwareAccelerationEnabled
.
asObservable
()
.
observeOn
(
MainScheduler
.
instance
)
.
bind
(
to
:
switchView
.
rx
.
value
)
.
disposed
(
by
:
cell
.
disposeBag
)
switchView
.
rx
.
value
.
observeOn
(
MainScheduler
.
instance
)
.
subscribe
(
onNext
:
{
[
weak
self
]
(
enable
)
in
self
?
.
viewModel
.
togleHardwareAcceleration
(
enable
:
enable
)
})
.
disposed
(
by
:
cell
.
disposeBag
)
return
cell
case
.
sectionHeader
(
let
title
):
let
cell
=
UITableViewCell
()
cell
.
textLabel
?
.
text
=
title
cell
.
backgroundColor
=
UIColor
.
jamiNavigationBar
cell
.
selectionStyle
=
.
none
cell
.
heightAnchor
.
constraint
(
equalToConstant
:
35
)
.
isActive
=
true
return
cell
}
}
let
settingsItemDataSource
=
RxTableViewSectionedReloadDataSource
<
GeneralSettingsSection
>
(
configureCell
:
configureCell
)
self
.
viewModel
.
generalSettings
.
bind
(
to
:
settingsTable
.
rx
.
items
(
dataSource
:
settingsItemDataSource
))
.
disposed
(
by
:
disposeBag
)
}