Ver código fonte

#2221

Signed-off-by: Marino Faggiana <marino@marinofaggiana.com>
Marino Faggiana 2 anos atrás
pai
commit
fef4f5fe29

+ 8 - 0
Nextcloud.xcodeproj/project.pbxproj

@@ -394,6 +394,8 @@
 		F7A0D1362591FBC5008F8A13 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extensions.swift */; };
 		F7A0D1372591FBC5008F8A13 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extensions.swift */; };
 		F7A321AD1E9E6AD50069AD1B /* CCAdvanced.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A321AC1E9E6AD50069AD1B /* CCAdvanced.m */; };
+		F7A60F86292D215000FCE1F2 /* NCTalkAccounts.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A60F84292D215000FCE1F2 /* NCTalkAccounts.swift */; };
+		F7A60F87292D215000FCE1F2 /* NCTalkAccounts.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7A60F85292D215000FCE1F2 /* NCTalkAccounts.storyboard */; };
 		F7A76DC8256A71CD00119AB3 /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B7504A2397D38E004E13EC /* UIImage+Extensions.swift */; };
 		F7A76DCD256A71CE00119AB3 /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B7504A2397D38E004E13EC /* UIImage+Extensions.swift */; };
 		F7A7FA6329265CF4000603EF /* NCManageE2EE.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A7FA6229265CF4000603EF /* NCManageE2EE.swift */; };
@@ -950,6 +952,8 @@
 		F7A0D1342591FBC5008F8A13 /* String+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = "<group>"; };
 		F7A321AB1E9E6AD50069AD1B /* CCAdvanced.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCAdvanced.h; sourceTree = "<group>"; };
 		F7A321AC1E9E6AD50069AD1B /* CCAdvanced.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCAdvanced.m; sourceTree = "<group>"; };
+		F7A60F84292D215000FCE1F2 /* NCTalkAccounts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCTalkAccounts.swift; sourceTree = "<group>"; };
+		F7A60F85292D215000FCE1F2 /* NCTalkAccounts.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCTalkAccounts.storyboard; sourceTree = "<group>"; };
 		F7A7FA6229265CF4000603EF /* NCManageE2EE.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCManageE2EE.swift; sourceTree = "<group>"; };
 		F7A8D72228F176B6008BBE1C /* WidgetDashboardIntentHandler-Brinding-header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WidgetDashboardIntentHandler-Brinding-header.h"; sourceTree = "<group>"; };
 		F7A8D73028F17C44008BBE1C /* WidgetDashboardIntentHandler.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WidgetDashboardIntentHandler.entitlements; sourceTree = "<group>"; };
@@ -1946,6 +1950,8 @@
 			children = (
 				F7CA212C25F1333200826ABB /* NCAccountRequest.storyboard */,
 				F7CA212B25F1333200826ABB /* NCAccountRequest.swift */,
+				F7A60F85292D215000FCE1F2 /* NCTalkAccounts.storyboard */,
+				F7A60F84292D215000FCE1F2 /* NCTalkAccounts.swift */,
 			);
 			path = "Account Request";
 			sourceTree = "<group>";
@@ -2703,6 +2709,7 @@
 				F70A58C024D0545100DED00D /* NCCapabilitiesViewController.storyboard in Resources */,
 				F7F4F10627ECDBDB008676F9 /* Inconsolata-Medium.ttf in Resources */,
 				F749C10D23C4A5340027D966 /* NCIntro.storyboard in Resources */,
+				F7A60F87292D215000FCE1F2 /* NCTalkAccounts.storyboard in Resources */,
 				F7239877253D86D300257F49 /* NCEmptyView.xib in Resources */,
 				F747BA1F22354D2000971601 /* NCCreateFormUploadVoiceNote.storyboard in Resources */,
 				F719D9E0288D37A300762E33 /* NCColorPicker.storyboard in Resources */,
@@ -2989,6 +2996,7 @@
 				F738E8421F90FFD100F95C8E /* NCManageEndToEndEncryption.m in Sources */,
 				F70753F12542A9A200972D44 /* NCViewerMedia.swift in Sources */,
 				F78A18B823CDE2B300F681F3 /* NCViewerRichWorkspace.swift in Sources */,
+				F7A60F86292D215000FCE1F2 /* NCTalkAccounts.swift in Sources */,
 				F77910AB25DD53C700CEDB9E /* NCSettingsBundleHelper.swift in Sources */,
 				AF4BF61927562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */,
 				F78A18B623CDD07D00F681F3 /* NCViewerRichWorkspaceWebView.swift in Sources */,

+ 149 - 0
iOSClient/Account Request/NCTalkAccounts.storyboard

@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="V0q-CP-xMJ">
+    <device id="retina6_0" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--Talk Accounts-->
+        <scene sceneID="L90-uG-f4z">
+            <objects>
+                <viewController id="V0q-CP-xMJ" customClass="NCTalkAccounts" customModule="Nextcloud" customModuleProvider="target" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="4vK-ua-S0e"/>
+                        <viewControllerLayoutGuide type="bottom" id="hTI-Bw-Fws"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="gzh-6E-hc4">
+                        <rect key="frame" x="0.0" y="0.0" width="300" height="310"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Accounts" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nZr-nE-ths">
+                                <rect key="frame" x="20" y="62" width="260" height="18"/>
+                                <fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/>
+                                <nil key="textColor"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QqL-qq-3JI">
+                                <rect key="frame" x="16" y="63.666666666666657" width="15" height="15"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="15" id="FJj-0n-59w"/>
+                                    <constraint firstAttribute="width" constant="15" id="FLg-jE-FHJ"/>
+                                </constraints>
+                                <state key="normal" image="xmark"/>
+                                <connections>
+                                    <action selector="actionClose:" destination="V0q-CP-xMJ" eventType="touchUpInside" id="4cX-K8-0C0"/>
+                                </connections>
+                            </button>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="Pdo-MB-AhU">
+                                <rect key="frame" x="10" y="95" width="280" height="215"/>
+                                <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="Cell" rowHeight="60" id="Q4K-la-J3W">
+                                        <rect key="frame" x="0.0" y="50" width="280" height="60"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Q4K-la-J3W" id="IkA-cK-iZV">
+                                            <rect key="frame" x="0.0" y="0.0" width="280" height="60"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <imageView clipsSubviews="YES" userInteractionEnabled="NO" tag="10" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="4cH-oC-YBd" userLabel="Avatar">
+                                                    <rect key="frame" x="0.0" y="15" width="30" height="30"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="30" id="Efd-BU-u61"/>
+                                                        <constraint firstAttribute="width" constant="30" id="qFy-Tu-ov6"/>
+                                                    </constraints>
+                                                </imageView>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="20" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pWI-iZ-BTy" userLabel="User">
+                                                    <rect key="frame" x="40" y="20.333333333333336" width="220" height="19.333333333333336"/>
+                                                    <fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
+                                                    <nil key="textColor"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <label opaque="NO" userInteractionEnabled="NO" tag="30" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sWT-NJ-ihR" userLabel="Url">
+                                                    <rect key="frame" x="40" y="40.666666666666664" width="220" height="16"/>
+                                                    <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                                                    <nil key="textColor"/>
+                                                    <nil key="highlightedColor"/>
+                                                </label>
+                                                <imageView clipsSubviews="YES" userInteractionEnabled="NO" tag="40" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="x47-dQ-alI" userLabel="Active">
+                                                    <rect key="frame" x="265" y="22.666666666666668" width="15" height="15.000000000000004"/>
+                                                    <constraints>
+                                                        <constraint firstAttribute="height" constant="15" id="SXt-LG-c5N"/>
+                                                        <constraint firstAttribute="width" constant="15" id="vdZ-4R-gY5"/>
+                                                    </constraints>
+                                                </imageView>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="4cH-oC-YBd" firstAttribute="leading" secondItem="IkA-cK-iZV" secondAttribute="leading" id="3cz-yE-yoQ"/>
+                                                <constraint firstAttribute="trailing" secondItem="x47-dQ-alI" secondAttribute="trailing" id="Dna-rj-LLQ"/>
+                                                <constraint firstItem="x47-dQ-alI" firstAttribute="centerY" secondItem="IkA-cK-iZV" secondAttribute="centerY" id="Ghs-sZ-Bzf"/>
+                                                <constraint firstItem="sWT-NJ-ihR" firstAttribute="leading" secondItem="4cH-oC-YBd" secondAttribute="trailing" constant="10" id="MxV-Du-vUw"/>
+                                                <constraint firstItem="4cH-oC-YBd" firstAttribute="centerY" secondItem="IkA-cK-iZV" secondAttribute="centerY" id="WuT-iT-3xk"/>
+                                                <constraint firstItem="sWT-NJ-ihR" firstAttribute="top" secondItem="pWI-iZ-BTy" secondAttribute="bottom" constant="1" id="ZVm-u7-JGI"/>
+                                                <constraint firstItem="x47-dQ-alI" firstAttribute="leading" secondItem="pWI-iZ-BTy" secondAttribute="trailing" constant="5" id="e8E-uH-gvt"/>
+                                                <constraint firstItem="pWI-iZ-BTy" firstAttribute="centerY" secondItem="IkA-cK-iZV" secondAttribute="centerY" id="jUS-89-RRO"/>
+                                                <constraint firstItem="x47-dQ-alI" firstAttribute="leading" secondItem="sWT-NJ-ihR" secondAttribute="trailing" constant="5" id="lIk-Sj-EgC"/>
+                                                <constraint firstItem="pWI-iZ-BTy" firstAttribute="leading" secondItem="4cH-oC-YBd" secondAttribute="trailing" constant="10" id="mlI-8s-1Ae"/>
+                                            </constraints>
+                                        </tableViewCellContentView>
+                                        <color key="backgroundColor" systemColor="secondarySystemGroupedBackgroundColor"/>
+                                    </tableViewCell>
+                                </prototypes>
+                                <connections>
+                                    <outlet property="dataSource" destination="V0q-CP-xMJ" id="xmA-NY-Eyz"/>
+                                    <outlet property="delegate" destination="V0q-CP-xMJ" id="j64-3x-N2u"/>
+                                </connections>
+                            </tableView>
+                            <progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="e8R-j7-ObS">
+                                <rect key="frame" x="0.0" y="308" width="300" height="2"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="2" id="G3U-2x-imL"/>
+                                </constraints>
+                                <color key="progressTintColor" systemColor="systemBlueColor"/>
+                            </progressView>
+                        </subviews>
+                        <color key="backgroundColor" systemColor="secondarySystemGroupedBackgroundColor"/>
+                        <constraints>
+                            <constraint firstItem="e8R-j7-ObS" firstAttribute="leading" secondItem="gzh-6E-hc4" secondAttribute="leading" id="1gS-Ca-1Ov"/>
+                            <constraint firstItem="Pdo-MB-AhU" firstAttribute="top" secondItem="nZr-nE-ths" secondAttribute="bottom" constant="15" id="5vV-YC-uzH"/>
+                            <constraint firstAttribute="trailing" secondItem="Pdo-MB-AhU" secondAttribute="trailing" constant="10" id="819-yV-vz7"/>
+                            <constraint firstItem="hTI-Bw-Fws" firstAttribute="top" secondItem="e8R-j7-ObS" secondAttribute="bottom" id="Cko-PC-TiW"/>
+                            <constraint firstAttribute="trailing" secondItem="nZr-nE-ths" secondAttribute="trailing" constant="20" id="DPW-MV-oKc"/>
+                            <constraint firstItem="hTI-Bw-Fws" firstAttribute="top" secondItem="Pdo-MB-AhU" secondAttribute="bottom" id="Ife-Ku-hGQ"/>
+                            <constraint firstItem="QqL-qq-3JI" firstAttribute="centerY" secondItem="nZr-nE-ths" secondAttribute="centerY" id="NpU-Hq-gMP"/>
+                            <constraint firstItem="nZr-nE-ths" firstAttribute="leading" secondItem="gzh-6E-hc4" secondAttribute="leading" constant="20" id="SI9-xL-6s8"/>
+                            <constraint firstItem="Pdo-MB-AhU" firstAttribute="leading" secondItem="gzh-6E-hc4" secondAttribute="leading" constant="10" id="Y5n-ju-hts"/>
+                            <constraint firstAttribute="trailing" secondItem="e8R-j7-ObS" secondAttribute="trailing" id="chh-t9-vJN"/>
+                            <constraint firstItem="QqL-qq-3JI" firstAttribute="leading" secondItem="gzh-6E-hc4" secondAttribute="leading" constant="16" id="gCH-qr-Dyd"/>
+                            <constraint firstItem="nZr-nE-ths" firstAttribute="top" secondItem="4vK-ua-S0e" secondAttribute="bottom" constant="15" id="oyJ-sj-j5N"/>
+                        </constraints>
+                    </view>
+                    <navigationItem key="navigationItem" id="Zon-2j-rsc"/>
+                    <size key="freeformSize" width="300" height="310"/>
+                    <connections>
+                        <outlet property="closeButton" destination="QqL-qq-3JI" id="6xR-LA-F9H"/>
+                        <outlet property="progressView" destination="e8R-j7-ObS" id="2gM-MB-IhE"/>
+                        <outlet property="tableView" destination="Pdo-MB-AhU" id="AcD-SW-2ga"/>
+                        <outlet property="titleLabel" destination="nZr-nE-ths" id="UbA-Dl-0Ad"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="qdm-Cl-C5l" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1453.125" y="133.75"/>
+        </scene>
+    </scenes>
+    <resources>
+        <image name="xmark" width="24" height="24"/>
+        <systemColor name="secondarySystemGroupedBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+        <systemColor name="systemBlueColor">
+            <color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+    </resources>
+</document>

+ 245 - 0
iOSClient/Account Request/NCTalkAccounts.swift

@@ -0,0 +1,245 @@
+//
+//  NCTalkAccounts.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 22/11/22.
+//  Copyright © 2021 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@nextcloud.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, see <http://www.gnu.org/licenses/>.
+//
+
+import UIKit
+import NextcloudKit
+
+public protocol NCTalkAccountsDelegate: AnyObject {
+    func accountRequestAddAccount()
+    func accountRequestChangeAccount(account: String)
+}
+
+// optional func
+public extension NCTalkAccountsDelegate {
+    func accountRequestAddAccount() {}
+    func accountRequestChangeAccount(account: String) {}
+}
+
+class NCTalkAccounts: UIViewController {
+
+    @IBOutlet weak var titleLabel: UILabel!
+    @IBOutlet weak var closeButton: UIButton!
+    @IBOutlet weak var tableView: UITableView!
+    @IBOutlet weak var progressView: UIProgressView!
+
+    public var accounts: [tableAccount] = []
+    public var activeAccount: tableAccount?
+    public let heightCell: CGFloat = 60
+    public var enableTimerProgress: Bool = true
+    public var enableAddAccount: Bool = false
+    public var dismissDidEnterBackground: Bool = false
+    public weak var delegate: NCTalkAccountsDelegate?
+
+    private var timer: Timer?
+    private var time: Float = 0
+    private let secondsAutoDismiss: Float = 3
+
+    // MARK: - View Life Cycle
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+
+        titleLabel.text = NSLocalizedString("_account_select_", comment: "")
+
+        closeButton.setImage(NCUtility.shared.loadImage(named: "xmark", color: .label), for: .normal)
+
+        tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 1))
+        tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
+
+        view.backgroundColor = .secondarySystemBackground
+        tableView.backgroundColor = .secondarySystemBackground
+
+        progressView.trackTintColor = .clear
+        progressView.progress = 1
+        if enableTimerProgress {
+            progressView.isHidden = false
+        } else {
+            progressView.isHidden = true
+        }
+
+        NotificationCenter.default.addObserver(self, selector: #selector(startTimer), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidBecomeActive), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidEnterBackground), object: nil)
+    }
+
+    override func viewWillAppear(_ animated: Bool) {
+        super.viewWillAppear(animated)
+    }
+
+    override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+
+        let visibleCells = tableView.visibleCells
+        var numAccounts = accounts.count
+        if enableAddAccount { numAccounts += 1 }
+
+        if visibleCells.count == numAccounts {
+            tableView.isScrollEnabled = false
+        }
+    }
+
+    override func viewWillDisappear(_ animated: Bool) {
+        super.viewWillDisappear(animated)
+
+        timer?.invalidate()
+    }
+
+    // MARK: - Action
+
+    @IBAction func actionClose(_ sender: UIButton) {
+        dismiss(animated: true)
+    }
+
+    // MARK: - NotificationCenter
+
+    @objc func applicationDidEnterBackground() {
+
+        if dismissDidEnterBackground {
+            dismiss(animated: false)
+        }
+    }
+
+    // MARK: - Progress
+
+    @objc func startTimer() {
+
+        if enableTimerProgress {
+            time = 0
+            timer?.invalidate()
+            timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateProgress), userInfo: nil, repeats: true)
+            progressView.isHidden = false
+        } else {
+            progressView.isHidden = true
+        }
+    }
+
+    @objc func updateProgress() {
+
+        time += 0.1
+        if time >= secondsAutoDismiss {
+            dismiss(animated: true)
+        } else {
+            progressView.progress = 1 - (time / secondsAutoDismiss)
+        }
+    }
+}
+
+extension NCTalkAccounts: UITableViewDelegate {
+
+    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
+
+        timer?.invalidate()
+        progressView.progress = 0
+    }
+
+    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
+        if decelerate {
+//            startTimer()
+        }
+    }
+
+    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
+//        startTimer()
+    }
+
+    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+        return heightCell
+    }
+
+    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+
+        if indexPath.row == accounts.count {
+
+            dismiss(animated: true)
+            delegate?.accountRequestAddAccount()
+
+        } else {
+
+            let account = accounts[indexPath.row]
+            if account.account != activeAccount?.account {
+                dismiss(animated: true) {
+                    self.delegate?.accountRequestChangeAccount(account: account.account)
+                }
+            } else {
+                dismiss(animated: true)
+            }
+        }
+    }
+}
+
+extension NCTalkAccounts: UITableViewDataSource {
+
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        if enableAddAccount {
+            return accounts.count + 1
+        } else {
+            return accounts.count
+        }
+    }
+
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+
+        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
+        cell.backgroundColor = tableView.backgroundColor
+
+        let avatarImage = cell.viewWithTag(10) as? UIImageView
+        let userLabel = cell.viewWithTag(20) as? UILabel
+        let urlLabel = cell.viewWithTag(30) as? UILabel
+        let activeImage = cell.viewWithTag(40) as? UIImageView
+
+        userLabel?.text = ""
+        urlLabel?.text = ""
+
+        if indexPath.row == accounts.count {
+
+            avatarImage?.image = NCUtility.shared.loadImage(named: "plus").image(color: .systemBlue, size: 15)
+            avatarImage?.contentMode = .center
+            userLabel?.text = NSLocalizedString("_add_account_", comment: "")
+            userLabel?.textColor = .systemBlue
+            userLabel?.font = UIFont.systemFont(ofSize: 15)
+
+        } else {
+
+            let account = accounts[indexPath.row]
+
+            avatarImage?.image = NCUtility.shared.loadUserImage(
+                for: account.user,
+                   displayName: account.displayName,
+                   userBaseUrl: account)
+
+            if account.alias.isEmpty {
+                userLabel?.text = account.user.uppercased()
+                urlLabel?.text = (URL(string: account.urlBase)?.host ?? "")
+            } else {
+                userLabel?.text = account.alias.uppercased()
+            }
+
+            if account.active {
+                activeImage?.image = NCUtility.shared.loadImage(named: "checkmark").image(color: .systemBlue, size: 30)
+            } else {
+                activeImage?.image = nil
+            }
+        }
+
+        return cell
+    }
+}

+ 1 - 0
iOSClient/Brand/NCBrand.swift

@@ -51,6 +51,7 @@ import UIKit
 
     // Capabilities Group
     @objc public var capabilitiesGroups: String = "group.it.twsweb.Crypto-Cloud"
+    @objc public var capabilitiesGroupsTalk: String = "group.com.nextcloud.Talk"
 
     // User Agent
     @objc public var userAgent: String = "Nextcloud-iOS"                                                            // Don't touch me !!

+ 1 - 0
iOSClient/Brand/iOSClient.entitlements

@@ -7,6 +7,7 @@
 	<key>com.apple.security.application-groups</key>
 	<array>
 		<string>group.it.twsweb.Crypto-Cloud</string>
+		<string>group.com.nextcloud.Talk</string>
 	</array>
 	<key>keychain-access-groups</key>
 	<array>

+ 35 - 0
iOSClient/Login/NCLogin.swift

@@ -23,6 +23,7 @@
 
 import UIKit
 import NextcloudKit
+import SwiftEntryKit
 
 class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
 
@@ -127,6 +128,15 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
         super.viewDidAppear(animated)
 
         appDelegate.timerErrorNetworking?.invalidate()
+
+        // test
+        createTalkAccount()
+
+        if let talkAccounts = readTalkAccounts(), let image = UIImage(named: "iconSuccess"), let backgroundColor =  NCBrandColor.shared.brandElement.lighter(by: 10) {
+            NCContentPresenter.shared.alertAction(image: image, backgroundColor: backgroundColor, textColor: textColor, title: "Talk is intalled", description: "Hei I have fount talk user, ...", textCancelButton: "cancel", textOkButton: "ok", attributes: EKAttributes.topFloat) { identifier in
+                print(identifier)
+            }
+        }
     }
 
     override func viewDidDisappear(_ animated: Bool) {
@@ -389,4 +399,29 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
             self.present(alertController, animated: true, completion: { })
         }
     }
+
+    func readTalkAccounts() -> [[String:String]]? {
+
+        guard let dirGroupTalk = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroupsTalk) else { return nil }
+        let url = dirGroupTalk.appendingPathComponent(NCGlobal.shared.appDatabaseTalk + "/" + NCGlobal.shared.fileAccounts)
+
+        if FileManager.default.fileExists(atPath: url.path) {
+            return NCUtility.shared.readAccountsFile(at: url)
+        }
+        return nil
+    }
+
+    func createTalkAccount() -> Error? {
+
+        guard let dirGroupTalk = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroupsTalk) else { return nil }
+        let url = dirGroupTalk.appendingPathComponent(NCGlobal.shared.appDatabaseTalk + "/" + NCGlobal.shared.fileAccounts)
+
+
+        let tableAccount = NCManageDatabase.shared.getAllAccount()
+        var accounts = [[String:String]]()
+        for account in tableAccount {
+            accounts.append([account.urlBase:account.user])
+        }
+        return NCUtility.shared.createAccountsFile(at: url, accounts: accounts)
+    }
 }

+ 2 - 0
iOSClient/NCGlobal.swift

@@ -89,6 +89,7 @@ class NCGlobal: NSObject {
     @objc let appDatabaseNextcloud                  = "Library/Application Support/Nextcloud"
     @objc let appScan                               = "Library/Application Support/Scan"
     @objc let appUserData                           = "Library/Application Support/UserData"
+    @objc let appDatabaseTalk                       = "Library/Application Support/Talk"
 
     // Service
     //
@@ -122,6 +123,7 @@ class NCGlobal: NSObject {
     //
     let databaseDefault                             = "nextcloud.realm"
     let databaseSchemaVersion: UInt64               = 255
+    let fileAccounts: String                        = "accounts.json"
 
     // Intro selector
     //

+ 55 - 0
iOSClient/Utility/NCContentPresenter.swift

@@ -148,6 +148,61 @@ class NCContentPresenter: NSObject {
         DispatchQueue.main.async { SwiftEntryKit.display(entry: contentView, using: attributes) }
     }
 
+    // MARK: -
+
+    func alertAction(image: UIImage, backgroundColor: UIColor, textColor: UIColor, title: String, description: String, textCancelButton: String, textOkButton: String, attributes: EKAttributes, completion: @escaping (_ identifier: String) -> Void) {
+
+        var buttonAttributes: EKAttributes {
+            var attributes = attributes
+            attributes.hapticFeedbackType = .success
+            attributes.displayDuration = .infinity
+            attributes.entryBackground = .color(color: EKColor(backgroundColor))
+            attributes.shadow = .active(with: .init(color: .black, opacity: 0.3, radius: 8))
+            attributes.screenInteraction = .dismiss
+            attributes.entryInteraction = .absorbTouches
+            attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
+            attributes.roundCorners = .all(radius: 25)
+            attributes.entranceAnimation = .init(translate: .init(duration: 0.7, spring: .init(damping: 1, initialVelocity: 0)), scale: .init(from: 1.05, to: 1, duration: 0.4, spring: .init(damping: 1, initialVelocity: 0)))
+            attributes.exitAnimation = .init(translate: .init(duration: 0.2))
+            attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.2)))
+            attributes.positionConstraints.verticalOffset = 20
+            attributes.positionConstraints.size = .init(width: .offset(value: 20), height: .intrinsic)
+            attributes.positionConstraints.maxSize = .init(width: .constant(value: min(UIScreen.main.bounds.width, UIScreen.main.bounds.height)), height: .intrinsic)
+            attributes.statusBar = .dark
+            return attributes
+        }
+
+        let simpleMessage = EKSimpleMessage(image: EKProperty.ImageContent(image: image, size: CGSize(width: 34, height: 34)),
+                                            title: EKProperty.LabelContent(text: title, style: .init(font: MainFont.medium.with(size: 15), color: EKColor(textColor)), accessibilityIdentifier: "title"),
+                                            description: EKProperty.LabelContent(text: description, style: .init( font: MainFont.light.with(size: 13), color: EKColor(textColor)), accessibilityIdentifier: "description"))
+
+        let cancelButton = EKProperty.ButtonContent(
+            label: EKProperty.LabelContent(text: textCancelButton, style: EKProperty.LabelStyle(font: MainFont.medium.with(size: 16), color: EKColor(textColor))),
+            backgroundColor: .clear,
+            highlightedBackgroundColor: EKColor(UIColor.lightGray),
+            accessibilityIdentifier: "close") {
+                SwiftEntryKit.dismiss()
+                completion("close")
+            }
+
+        let okButton = EKProperty.ButtonContent(
+            label: EKProperty.LabelContent(text: textOkButton,style: EKProperty.LabelStyle(font: MainFont.medium.with(size: 16), color: EKColor(textColor))),
+            backgroundColor: .clear,
+            highlightedBackgroundColor: EKColor(UIColor.lightGray),
+            displayMode: EKAttributes.DisplayMode.inferred,
+            accessibilityIdentifier: "ok") {
+                SwiftEntryKit.dismiss()
+                completion("ok")
+            }
+
+        let buttonsBarContent = EKProperty.ButtonBarContent(with: cancelButton, okButton, separatorColor: EKColor(UIColor.lightGray), buttonHeight: 60, expandAnimatedly: true)
+        let alertMessage = EKAlertMessage(simpleMessage: simpleMessage, imagePosition: .left, buttonBarContent: buttonsBarContent)
+        let contentView = EKAlertMessageView(with: alertMessage)
+
+        SwiftEntryKit.display(entry: contentView, using: buttonAttributes)
+    }
+
+
     // MARK: - Note Message
 
     func noteTop(text: String, image: UIImage?, color: UIColor? = nil, type: messageType? = nil, delay: TimeInterval, priority: EKAttributes.Precedence.Priority = .normal, dropEnqueuedEntries: Bool = false) {

+ 24 - 0
iOSClient/Utility/NCUtility.swift

@@ -1074,4 +1074,28 @@ class NCUtility: NSObject {
 
         return false
     }
+
+    //
+
+    @objc func createAccountsFile(at url: URL, accounts: [[String:String]]) -> Error? {
+
+        do {
+            let encode = try JSONEncoder().encode(accounts)
+            try encode.write(to: url)
+        } catch {
+            return error
+        }
+        return nil
+    }
+
+    @objc func readAccountsFile(at url: URL) -> [[String:String]]? {
+
+        do {
+            let data = try Data(contentsOf: url)
+            let accounts: [[String:String]] = try JSONDecoder().decode([[String: String]].self, from: data)
+            return accounts
+        } catch {
+            return nil
+        }
+    }
 }