TF-250 Service view

This commit is contained in:
Zbigniew Cisiński 2024-04-11 23:13:22 +02:00
parent 1b43a4431f
commit 37886fb11f
9 changed files with 126 additions and 53 deletions

View File

@ -390,6 +390,7 @@
C25E8994266402AD00A60CE5 /* SectionEntity+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25E8992266402AD00A60CE5 /* SectionEntity+CoreDataClass.swift */; }; C25E8994266402AD00A60CE5 /* SectionEntity+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25E8992266402AD00A60CE5 /* SectionEntity+CoreDataClass.swift */; };
C25E8995266402AD00A60CE5 /* SectionEntity+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25E8993266402AD00A60CE5 /* SectionEntity+CoreDataProperties.swift */; }; C25E8995266402AD00A60CE5 /* SectionEntity+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25E8993266402AD00A60CE5 /* SectionEntity+CoreDataProperties.swift */; };
C25F4FDB2622207F008F7755 /* TokensViewEmptySearchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25F4FDA2622207F008F7755 /* TokensViewEmptySearchScreen.swift */; }; C25F4FDB2622207F008F7755 /* TokensViewEmptySearchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25F4FDA2622207F008F7755 /* TokensViewEmptySearchScreen.swift */; };
C260DCC22BC885F1007807CC /* ServiceCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C260DCC12BC885F1007807CC /* ServiceCellView.swift */; };
C2625F8C28BB853D00D84C5C /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2625F8B28BB853D00D84C5C /* AboutViewController.swift */; }; C2625F8C28BB853D00D84C5C /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2625F8B28BB853D00D84C5C /* AboutViewController.swift */; };
C2625F8E28BB858600D84C5C /* AboutPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2625F8D28BB858600D84C5C /* AboutPresenter.swift */; }; C2625F8E28BB858600D84C5C /* AboutPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2625F8D28BB858600D84C5C /* AboutPresenter.swift */; };
C2625F9028BB85B100D84C5C /* AboutModuleInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2625F8F28BB85B100D84C5C /* AboutModuleInteractor.swift */; }; C2625F9028BB85B100D84C5C /* AboutModuleInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2625F8F28BB85B100D84C5C /* AboutModuleInteractor.swift */; };
@ -2273,6 +2274,8 @@
C25E8992266402AD00A60CE5 /* SectionEntity+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SectionEntity+CoreDataClass.swift"; sourceTree = "<group>"; }; C25E8992266402AD00A60CE5 /* SectionEntity+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SectionEntity+CoreDataClass.swift"; sourceTree = "<group>"; };
C25E8993266402AD00A60CE5 /* SectionEntity+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SectionEntity+CoreDataProperties.swift"; sourceTree = "<group>"; }; C25E8993266402AD00A60CE5 /* SectionEntity+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SectionEntity+CoreDataProperties.swift"; sourceTree = "<group>"; };
C25F4FDA2622207F008F7755 /* TokensViewEmptySearchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokensViewEmptySearchScreen.swift; sourceTree = "<group>"; }; C25F4FDA2622207F008F7755 /* TokensViewEmptySearchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokensViewEmptySearchScreen.swift; sourceTree = "<group>"; };
C260DCC02BC882AD007807CC /* TwoFASWatch-Watch-App-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "TwoFASWatch-Watch-App-Info.plist"; sourceTree = SOURCE_ROOT; };
C260DCC12BC885F1007807CC /* ServiceCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceCellView.swift; sourceTree = "<group>"; };
C261A1212A12BECC00A1519F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/TwoFASWidget.strings; sourceTree = "<group>"; }; C261A1212A12BECC00A1519F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/TwoFASWidget.strings; sourceTree = "<group>"; };
C261A1222A12BECC00A1519F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; }; C261A1222A12BECC00A1519F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
C261A1232A12BECD00A1519F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = "<group>"; }; C261A1232A12BECD00A1519F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@ -5667,6 +5670,7 @@
C274C9CE2BAB8ABB008E7212 /* TwoFASWatch Watch App */ = { C274C9CE2BAB8ABB008E7212 /* TwoFASWatch Watch App */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
C260DCC02BC882AD007807CC /* TwoFASWatch-Watch-App-Info.plist */,
C274CAA02BAB98A5008E7212 /* TwoFASWatch Watch App.entitlements */, C274CAA02BAB98A5008E7212 /* TwoFASWatch Watch App.entitlements */,
C274C9CF2BAB8ABB008E7212 /* TwoFASWatchApp.swift */, C274C9CF2BAB8ABB008E7212 /* TwoFASWatchApp.swift */,
C274C9D12BAB8ABB008E7212 /* ContentView.swift */, C274C9D12BAB8ABB008E7212 /* ContentView.swift */,
@ -5683,6 +5687,7 @@
C2B86D272BC32FA300AAAC63 /* InteractorFactory.swift */, C2B86D272BC32FA300AAAC63 /* InteractorFactory.swift */,
C2B86D292BC33D3000AAAC63 /* AppDelegateInteractor.swift */, C2B86D292BC33D3000AAAC63 /* AppDelegateInteractor.swift */,
C2B86D2B2BC3492A00AAAC63 /* Service.swift */, C2B86D2B2BC3492A00AAAC63 /* Service.swift */,
C260DCC12BC885F1007807CC /* ServiceCellView.swift */,
C268918E2BC4974800713078 /* Category.swift */, C268918E2BC4974800713078 /* Category.swift */,
C268918B2BC4960C00713078 /* ServiceList */, C268918B2BC4960C00713078 /* ServiceList */,
C2627F382BC72E19009F93A9 /* Service */, C2627F382BC72E19009F93A9 /* Service */,
@ -10088,6 +10093,7 @@
C268918F2BC4974800713078 /* Category.swift in Sources */, C268918F2BC4974800713078 /* Category.swift in Sources */,
C2B86D302BC349AE00AAAC63 /* MainPresenter.swift in Sources */, C2B86D302BC349AE00AAAC63 /* MainPresenter.swift in Sources */,
C2B86D262BC32F9200AAAC63 /* MainInteractor.swift in Sources */, C2B86D262BC32F9200AAAC63 /* MainInteractor.swift in Sources */,
C260DCC22BC885F1007807CC /* ServiceCellView.swift in Sources */,
C2B86D242BC3070F00AAAC63 /* AppPIN.swift in Sources */, C2B86D242BC3070F00AAAC63 /* AppPIN.swift in Sources */,
C2627F3C2BC72EA0009F93A9 /* ServiceInteractor.swift in Sources */, C2627F3C2BC72EA0009F93A9 /* ServiceInteractor.swift in Sources */,
); );
@ -11956,6 +11962,7 @@
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17; GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "TwoFASWatch-Watch-App-Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = TwoFASWatch; INFOPLIST_KEY_CFBundleDisplayName = TwoFASWatch;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
@ -11998,6 +12005,7 @@
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17; GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "TwoFASWatch-Watch-App-Info.plist";
INFOPLIST_KEY_CFBundleDisplayName = TwoFASWatch; INFOPLIST_KEY_CFBundleDisplayName = TwoFASWatch;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";

View File

@ -26,7 +26,10 @@ final class AppDelegateInteractor: NSObject, WKApplicationDelegate {
func applicationDidFinishLaunching() { func applicationDidFinishLaunching() {
if !WKApplication.shared().isRegisteredForRemoteNotifications { if !WKApplication.shared().isRegisteredForRemoteNotifications {
Log("Registering Push Notifications")
WKApplication.shared().registerForRemoteNotifications() WKApplication.shared().registerForRemoteNotifications()
} else {
Log("Push Notifications registered")
} }
mainRepository.registerForCloudStateChanges({ [weak self] state in mainRepository.registerForCloudStateChanges({ [weak self] state in
Log("Cloud state changed: \(state)") Log("Cloud state changed: \(state)")

View File

@ -34,19 +34,8 @@ struct MainView: View {
interactor: InteractorFactory.shared.serviceInteractor(service: service) interactor: InteractorFactory.shared.serviceInteractor(service: service)
) )
) )
) { ) {
VStack(alignment: .leading) { ServiceCellView(service: service)
Text(service.name)
.font(.callout)
.padding(4)
.foregroundStyle(.primary)
if let additionalInfo = service.additionalInfo {
Text(additionalInfo)
.padding(.horizontal, 4)
.font(.caption2)
.foregroundStyle(.secondary)
}
}
} }
} }
} }

View File

@ -59,6 +59,7 @@ extension ServiceInteractor: ServiceInteracting {
counter: 0, counter: 0,
tokenType: serviceData.tokenType tokenType: serviceData.tokenType
) )
.formattedValue(for: serviceData.tokenType)
} }
func timeToNextDate(for date: Date) -> Date { func timeToNextDate(for date: Date) -> Date {

View File

@ -30,6 +30,8 @@ final class ServicePresenter: ObservableObject {
init(interactor: ServiceInteracting) { init(interactor: ServiceInteracting) {
self.interactor = interactor self.interactor = interactor
interactor.initialize()
name = interactor.service.name name = interactor.service.name
additionalInfo = interactor.service.additionalInfo additionalInfo = interactor.service.additionalInfo
service = interactor.service service = interactor.service

View File

@ -27,41 +27,67 @@ struct ServiceView: View {
var presenter: ServicePresenter var presenter: ServicePresenter
private let spacing: CGFloat = 8 private let spacing: CGFloat = 8
@ViewBuilder @ViewBuilder
var body: some View { var body: some View {
VStack(alignment: .leading, spacing: nil) { // Spacer()
Spacer()
TimelineView(.explicit(presenter.timelineEntries())) { context in TimelineView(.explicit(presenter.timelineEntries())) { context in
HStack(alignment: .center, spacing: nil) { VStack(alignment: .leading, spacing: nil) {
IconRenderer(service: presenter.service) HStack(alignment: .center, spacing: nil) {
Spacer() IconRenderer(service: presenter.service)
counterText(for: presenter.timeToNextDate(for: context.date)) Spacer()
.multilineTextAlignment(.trailing) counterText(for: presenter.timeToNextDate(for: context.date))
.font(Font.body.monospacedDigit()) .multilineTextAlignment(.trailing)
.lineLimit(1) .font(Font.body.monospacedDigit())
.contentTransition(.numericText(countsDown: true))
}
Spacer(minLength: spacing * 3)
VStack(alignment: .leading, spacing: 3) {
Text(presenter.name)
.font(.caption)
.multilineTextAlignment(.leading)
Text(presenter.calculateToken(for: context.date))
.font(Font.system(.title).weight(.light).monospacedDigit())
.multilineTextAlignment(.leading)
.minimumScaleFactor(0.2)
.contentTransition(.numericText())
if let info = presenter.additionalInfo {
Text(info)
.lineLimit(1) .lineLimit(1)
.font(.caption) .contentTransition(.numericText(countsDown: true))
.foregroundColor(.gray)
} }
// Spacer(minLength: spacing * 3)
Spacer()
VStack(alignment: .leading, spacing: 3) {
// Text(presenter.name)
// .font(.caption)
// .multilineTextAlignment(.leading)
// .lineLimit(1)
Text(presenter.calculateToken(for: context.date))
.font(Font.system(.title).weight(.light).monospacedDigit())
.multilineTextAlignment(.leading)
.minimumScaleFactor(0.2)
.contentTransition(.numericText())
.foregroundColor(.primary)
.layoutPriority(1)
// .background(Material.ultraThin, in: RoundedRectangle(cornerRadius: 8))
if let info = presenter.additionalInfo {
Text(info)
.lineLimit(1)
.font(.caption2)
.foregroundColor(.secondary)
.multilineTextAlignment(.leading)
}
Spacer()
.frame(maxHeight: .infinity)
}
.frame(alignment: .leading)
.padding(.top, 4)
} }
}
Spacer()
} }
.navigationTitle {
Text(presenter.name)
.lineLimit(1)
}
.toolbar {
ToolbarItem(placement: .bottomBar) {
Button {
print("Test")
} label: {
Image(systemName:"star")
}
.controlSize(.mini)
.background(Color.accentColor, in: Circle())
}
}
.scenePadding()
// .background(Color.accentColor.gradient)
} }
@ViewBuilder @ViewBuilder

View File

@ -0,0 +1,45 @@
//
// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
// Copyright © 2024 Two Factor Authentication Service, Inc.
// Contributed by Zbigniew Cisiński. All rights reserved.
//
// 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
// 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 <https://www.gnu.org/licenses/>
//
import SwiftUI
struct ServiceCellView: View {
let service: Service
var body: some View {
HStack(alignment: .center, spacing: 8) {
Rectangle()
.fill(service.badgeColor)
.frame(width: 20)
IconRenderer(service: service)
VStack(alignment: .leading, spacing: 8) {
Text(service.name)
.font(.callout)
.padding(4)
.foregroundStyle(.primary)
if let additionalInfo = service.additionalInfo {
Text(additionalInfo)
.padding(.horizontal, 4)
.font(.caption2)
.foregroundStyle(.secondary)
}
}
}
}
}

View File

@ -35,18 +35,7 @@ struct ServiceListView: View {
) )
) )
) { ) {
VStack(alignment: .leading) { ServiceCellView(service: service)
Text(service.name)
.font(.callout)
.padding(4)
.foregroundStyle(.primary)
if let additionalInfo = service.additionalInfo {
Text(additionalInfo)
.padding(.horizontal, 4)
.font(.caption2)
.foregroundStyle(.secondary)
}
}
} }
} }
} }

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
</dict>
</plist>