initial commit
This commit is contained in:
54
.gitignore
vendored
Normal file
54
.gitignore
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/xcode,macos
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=xcode,macos
|
||||||
|
|
||||||
|
### macOS ###
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
### macOS Patch ###
|
||||||
|
# iCloud generated files
|
||||||
|
*.icloud
|
||||||
|
|
||||||
|
### Xcode ###
|
||||||
|
## User settings
|
||||||
|
xcuserdata/
|
||||||
|
|
||||||
|
## Xcode 8 and earlier
|
||||||
|
*.xcscmblueprint
|
||||||
|
*.xccheckout
|
||||||
|
|
||||||
|
### Xcode Patch ###
|
||||||
|
*.xcodeproj/*
|
||||||
|
!*.xcodeproj/project.pbxproj
|
||||||
|
!*.xcodeproj/xcshareddata/
|
||||||
|
!*.xcodeproj/project.xcworkspace/
|
||||||
|
!*.xcworkspace/contents.xcworkspacedata
|
||||||
|
/*.gcno
|
||||||
|
**/xcshareddata/WorkspaceSettings.xcsettings
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/xcode,macos
|
@@ -7,6 +7,9 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
F12B73452C55505E0064A230 /* NeuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F12B73442C55505E0064A230 /* NeuButton.swift */; };
|
||||||
|
F12B73472C55AC6B0064A230 /* PlaybackManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F12B73462C55AC6B0064A230 /* PlaybackManager.swift */; };
|
||||||
|
F12B73492C55C0C40064A230 /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = F12B73482C55C0C40064A230 /* .gitignore */; };
|
||||||
F13839702C51BABD00B4814F /* InfinifiIOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = F138396F2C51BABD00B4814F /* InfinifiIOSApp.swift */; };
|
F13839702C51BABD00B4814F /* InfinifiIOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = F138396F2C51BABD00B4814F /* InfinifiIOSApp.swift */; };
|
||||||
F13839722C51BABD00B4814F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F13839712C51BABD00B4814F /* ContentView.swift */; };
|
F13839722C51BABD00B4814F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F13839712C51BABD00B4814F /* ContentView.swift */; };
|
||||||
F13839742C51BABE00B4814F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F13839732C51BABE00B4814F /* Assets.xcassets */; };
|
F13839742C51BABE00B4814F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F13839732C51BABE00B4814F /* Assets.xcassets */; };
|
||||||
@@ -14,6 +17,9 @@
|
|||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
F12B73442C55505E0064A230 /* NeuButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeuButton.swift; sourceTree = "<group>"; };
|
||||||
|
F12B73462C55AC6B0064A230 /* PlaybackManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackManager.swift; sourceTree = "<group>"; };
|
||||||
|
F12B73482C55C0C40064A230 /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = SOURCE_ROOT; };
|
||||||
F138396C2C51BABD00B4814F /* InfinifiIOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = InfinifiIOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
F138396C2C51BABD00B4814F /* InfinifiIOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = InfinifiIOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
F138396F2C51BABD00B4814F /* InfinifiIOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfinifiIOSApp.swift; sourceTree = "<group>"; };
|
F138396F2C51BABD00B4814F /* InfinifiIOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfinifiIOSApp.swift; sourceTree = "<group>"; };
|
||||||
F13839712C51BABD00B4814F /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
F13839712C51BABD00B4814F /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||||
@@ -55,6 +61,9 @@
|
|||||||
F13839712C51BABD00B4814F /* ContentView.swift */,
|
F13839712C51BABD00B4814F /* ContentView.swift */,
|
||||||
F13839732C51BABE00B4814F /* Assets.xcassets */,
|
F13839732C51BABE00B4814F /* Assets.xcassets */,
|
||||||
F13839752C51BABE00B4814F /* Preview Content */,
|
F13839752C51BABE00B4814F /* Preview Content */,
|
||||||
|
F12B73442C55505E0064A230 /* NeuButton.swift */,
|
||||||
|
F12B73462C55AC6B0064A230 /* PlaybackManager.swift */,
|
||||||
|
F12B73482C55C0C40064A230 /* .gitignore */,
|
||||||
);
|
);
|
||||||
path = InfinifiIOS;
|
path = InfinifiIOS;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -126,6 +135,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
F13839772C51BABE00B4814F /* Preview Assets.xcassets in Resources */,
|
F13839772C51BABE00B4814F /* Preview Assets.xcassets in Resources */,
|
||||||
|
F12B73492C55C0C40064A230 /* .gitignore in Resources */,
|
||||||
F13839742C51BABE00B4814F /* Assets.xcassets in Resources */,
|
F13839742C51BABE00B4814F /* Assets.xcassets in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -137,7 +147,9 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
F12B73452C55505E0064A230 /* NeuButton.swift in Sources */,
|
||||||
F13839722C51BABD00B4814F /* ContentView.swift in Sources */,
|
F13839722C51BABD00B4814F /* ContentView.swift in Sources */,
|
||||||
|
F12B73472C55AC6B0064A230 /* PlaybackManager.swift in Sources */,
|
||||||
F13839702C51BABD00B4814F /* InfinifiIOSApp.swift in Sources */,
|
F13839702C51BABD00B4814F /* InfinifiIOSApp.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -275,6 +287,7 @@
|
|||||||
DEVELOPMENT_TEAM = 5FG7YZ49ZA;
|
DEVELOPMENT_TEAM = 5FG7YZ49ZA;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = infinifi;
|
||||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
@@ -304,6 +317,7 @@
|
|||||||
DEVELOPMENT_TEAM = 5FG7YZ49ZA;
|
DEVELOPMENT_TEAM = 5FG7YZ49ZA;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = infinifi;
|
||||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
|
38
InfinifiIOS/Assets.xcassets/BaseColor.colorset/Contents.json
Normal file
38
InfinifiIOS/Assets.xcassets/BaseColor.colorset/Contents.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xF5",
|
||||||
|
"green" : "0xF1",
|
||||||
|
"red" : "0xEF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x2E",
|
||||||
|
"green" : "0x1E",
|
||||||
|
"red" : "0x1E"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xCC",
|
||||||
|
"green" : "0xC0",
|
||||||
|
"red" : "0xBC"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x5A",
|
||||||
|
"green" : "0x47",
|
||||||
|
"red" : "0x45"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
38
InfinifiIOS/Assets.xcassets/TextColor.colorset/Contents.json
Normal file
38
InfinifiIOS/Assets.xcassets/TextColor.colorset/Contents.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x5A",
|
||||||
|
"green" : "0x47",
|
||||||
|
"red" : "0x45"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0xF4",
|
||||||
|
"green" : "0xD6",
|
||||||
|
"red" : "0xCD"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
@@ -1,21 +1,48 @@
|
|||||||
//
|
import AVKit
|
||||||
// ContentView.swift
|
|
||||||
// InfinifiIOS
|
|
||||||
//
|
|
||||||
// Created by Kenneth on 24/07/2024.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
var body: some View {
|
@ObservedObject private var playbackManager = PlaybackManager()
|
||||||
VStack {
|
|
||||||
Image(systemName: "globe")
|
private func toggleAudioPlayback() {
|
||||||
.imageScale(.large)
|
switch playbackManager.playbackState {
|
||||||
.foregroundStyle(.tint)
|
case .playing:
|
||||||
Text("Hello, world!")
|
playbackManager.stop()
|
||||||
|
case .paused:
|
||||||
|
playbackManager.nextTrack()
|
||||||
}
|
}
|
||||||
.padding()
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
let buttonImageName = switch playbackManager.playbackState {
|
||||||
|
case .paused: "play"
|
||||||
|
case .playing: "pause"
|
||||||
|
}
|
||||||
|
|
||||||
|
VStack(alignment: .center) {
|
||||||
|
Text("infinifi")
|
||||||
|
.font(.title3)
|
||||||
|
.bold()
|
||||||
|
.monospaced()
|
||||||
|
.padding()
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
NeuButton(action: {
|
||||||
|
toggleAudioPlayback()
|
||||||
|
}) {
|
||||||
|
Image(systemName: buttonImageName)
|
||||||
|
.font(.system(size: 24))
|
||||||
|
.tint(.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.frame(
|
||||||
|
maxWidth: .infinity,
|
||||||
|
maxHeight: .infinity
|
||||||
|
)
|
||||||
|
.background(.base)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,3 @@
|
|||||||
//
|
|
||||||
// InfinifiIOSApp.swift
|
|
||||||
// InfinifiIOS
|
|
||||||
//
|
|
||||||
// Created by Kenneth on 24/07/2024.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
@main
|
@main
|
||||||
|
63
InfinifiIOS/NeuButton.swift
Normal file
63
InfinifiIOS/NeuButton.swift
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct NeuButtonStyle: PrimitiveButtonStyle {
|
||||||
|
private let onPressStateChange: (_ isPressed: Bool) -> Void
|
||||||
|
private let impact = UIImpactFeedbackGenerator(style: .medium)
|
||||||
|
|
||||||
|
init(onPressStateChange: @escaping (_: Bool) -> Void) {
|
||||||
|
self.onPressStateChange = onPressStateChange
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeBody(configuration: Configuration) -> some View {
|
||||||
|
configuration.label
|
||||||
|
.onTapGesture {
|
||||||
|
configuration.trigger()
|
||||||
|
}
|
||||||
|
.onLongPressGesture(minimumDuration: 0) {} onPressingChanged: { isPressing in
|
||||||
|
onPressStateChange(isPressing)
|
||||||
|
impact.impactOccurred()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NeuButton<Content>: View where Content: View {
|
||||||
|
let content: () -> Content
|
||||||
|
let action: () -> Void
|
||||||
|
|
||||||
|
@State private var isPressed = false
|
||||||
|
|
||||||
|
init(action: @escaping () -> Void, @ViewBuilder content: @escaping () -> Content) {
|
||||||
|
self.content = content
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button(action: action) {
|
||||||
|
Rectangle()
|
||||||
|
.fill(isPressed ? .base : .text)
|
||||||
|
.offset(
|
||||||
|
x: isPressed ? 0 : 4,
|
||||||
|
y: isPressed ? 0 : 4
|
||||||
|
)
|
||||||
|
.overlay {
|
||||||
|
ZStack {
|
||||||
|
Rectangle()
|
||||||
|
.fill(isPressed ? .text : .base)
|
||||||
|
|
||||||
|
content()
|
||||||
|
.foregroundStyle(isPressed ? .base : .text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.border(.text, width: 2)
|
||||||
|
.frame(width: 64, height: 64)
|
||||||
|
.offset(
|
||||||
|
x: isPressed ? 6 : 0,
|
||||||
|
y: isPressed ? 6 : 0
|
||||||
|
)
|
||||||
|
.buttonStyle(NeuButtonStyle { isPressed in
|
||||||
|
self.isPressed = isPressed
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
39
InfinifiIOS/PlaybackManager.swift
Normal file
39
InfinifiIOS/PlaybackManager.swift
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import AVKit
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum PlaybackState {
|
||||||
|
case playing
|
||||||
|
case paused
|
||||||
|
}
|
||||||
|
|
||||||
|
class PlaybackManager: ObservableObject {
|
||||||
|
@Published var playbackState: PlaybackState = .paused
|
||||||
|
@Published var hasError = false
|
||||||
|
|
||||||
|
private var audioPlayer = AVPlayer()
|
||||||
|
|
||||||
|
func nextTrack() {
|
||||||
|
let now = Date().timeIntervalSince1970
|
||||||
|
// add timestamp to the url to prevent caching
|
||||||
|
let playerItem = AVPlayerItem(url: URL(string: "https://infinifi.cafe/current.mp3?t=\(now)")!)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(playbackFinished), name: AVPlayerItem.didPlayToEndTimeNotification, object: playerItem)
|
||||||
|
|
||||||
|
audioPlayer.replaceCurrentItem(with: playerItem)
|
||||||
|
audioPlayer.play()
|
||||||
|
|
||||||
|
playbackState = .playing
|
||||||
|
}
|
||||||
|
|
||||||
|
func stop() {
|
||||||
|
audioPlayer.pause()
|
||||||
|
playbackState = .paused
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
private func playbackFinished() {
|
||||||
|
NotificationCenter.default.removeObserver(self, name: AVPlayerItem.didPlayToEndTimeNotification, object: audioPlayer.currentItem)
|
||||||
|
if playbackState == .playing {
|
||||||
|
nextTrack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user