diff --git a/app/LandinhoLib/Sources/BetaSheet/Assets.xcassets/AppIcon.imageset/Contents.json b/app/LandinhoLib/Sources/BetaSheet/Assets.xcassets/AppIcon.imageset/Contents.json index adc7499..b6f10aa 100644 --- a/app/LandinhoLib/Sources/BetaSheet/Assets.xcassets/AppIcon.imageset/Contents.json +++ b/app/LandinhoLib/Sources/BetaSheet/Assets.xcassets/AppIcon.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Race Car Illustration DALL·E.png", + "filename" : "Race Car Illustration Sao Paulo.png", "idiom" : "universal" } ], diff --git "a/app/LandinhoLib/Sources/BetaSheet/Assets.xcassets/AppIcon.imageset/Race Car Illustration DALL\302\267E.png" "b/app/LandinhoLib/Sources/BetaSheet/Assets.xcassets/AppIcon.imageset/Race Car Illustration DALL\302\267E.png" deleted file mode 100644 index 3bf2c00..0000000 Binary files "a/app/LandinhoLib/Sources/BetaSheet/Assets.xcassets/AppIcon.imageset/Race Car Illustration DALL\302\267E.png" and /dev/null differ diff --git a/app/LandinhoLib/Sources/BetaSheet/Assets.xcassets/AppIcon.imageset/Race Car Illustration Sao Paulo.png b/app/LandinhoLib/Sources/BetaSheet/Assets.xcassets/AppIcon.imageset/Race Car Illustration Sao Paulo.png new file mode 100644 index 0000000..3bff92d Binary files /dev/null and b/app/LandinhoLib/Sources/BetaSheet/Assets.xcassets/AppIcon.imageset/Race Car Illustration Sao Paulo.png differ diff --git a/app/LandinhoLib/Sources/BetaSheet/BetaSheet.swift b/app/LandinhoLib/Sources/BetaSheet/BetaSheet.swift index b883ae8..af16746 100644 --- a/app/LandinhoLib/Sources/BetaSheet/BetaSheet.swift +++ b/app/LandinhoLib/Sources/BetaSheet/BetaSheet.swift @@ -76,15 +76,20 @@ public struct BetaSheet: View { let issues: LocalizedStringKey = """ • Design obviamente não está nem um pouco próximo de estar pronto • App não tem cache em nada. Tudo vai ser recarregado quando o app inicia - • A tela de categorias não tem função alguma. Quer ver as corridas de alguma categoria específica? Entra na tela de Admin pra ver • Eventos principais na tela de detalhe não tem informação da data - • Quando existem apenas dois eventos principais na tela de detalhe, o layout é meio esquisito • O botão de um Widget pequeno não está funcionando quando colocado na Home • Na home provisória, passar para o próximo evento de um widget pequeno afeta TODOS os widgets pequenos - • Erros atualmente mostram o payload completo do erro + • Erros atualmente mostram o payload completo do erro (Intencional, por enquanto) """ let latestRelease: LocalizedStringKey = """ + 24/11 + • Melhora o layout quando existe mais de um evento principal em uma corrida + • Remove aquele monte de widgets da home por uma lista que faz um pouco mais de sentido + • É possível compartilhar uma corrida a partir da Home agora + • Simplifica o fluxo de compartilhar uma corrida + • Adiciona a opção de remover sessões de treino de um Widget + 22/11 • Corrige um crash quando o app troca de telas • Corrige um problema onde o botão de voltar na tela de compartilhar não aparece em iPhones de tela pequena @@ -107,25 +112,22 @@ public struct BetaSheet: View { """ let nextSteps: LocalizedStringKey = """ - Esta lista será completamente limpa antes do lançamento público do aplicativo + Esta lista será completamente limpa antes do lançamento público do aplicativo (em ordem de prioridade) - • Ícone de verdade desenhado por um ser humano e não a aberração atual - • Compartilhar uma corrida direto da Home + • Os widgets deixarão de mostrar os horários de eventos que já se passaram (ex.: deixa de mostrar o treino livre se é a hora da classificação) + • Tela Sobre o desenvolvedor • Imagem de fundo ao compartilhar uma corrida por imagem - • Opção de remover sessões de treino de um Widget pequeno - • Compartilhar texto de uma corrida -> Estilo o bot - • Botão de voltar tela será reposicionado na tela de compartilhar corrida + • App Clip + • Botão de compartilhar o app em Ajustes -> App Clip ou Link • Parte de administração das categorias será escondida e protegida por senha • Adicionar cores para as categorias - • O widget pequeno deixará de mostrar os horários de eventos que já se passaram (ex.: deixa de mostrar o treino livre se é a hora da classificação) • Categorias terão uma "accent color" • Home de verdade, com os horários de todas as categorias, categorias favoritas aparecendo primeiro e paginação - • App Clip - • Botão de compartilhar o app em Ajustes -> App Clip ou Link - • Tela sobre o desenvolvedor • Ações rápidas no ícone do aplicativo • Design final da Home, Tela de Corrida, Categorias, Ajustes, Compartilhar, etc para iOS e iPadOS • Widget extra-largo para iPads + • Ícone de verdade desenhado por um ser humano e não a aberração atual + • Compartilhar texto de uma corrida -> Estilo o bot Para o futuro: • Notificações quando eventos específicos forem começar diff --git a/app/LandinhoLib/Sources/Categories/Categories.swift b/app/LandinhoLib/Sources/Categories/Categories.swift index c73ac4d..3840b97 100644 --- a/app/LandinhoLib/Sources/Categories/Categories.swift +++ b/app/LandinhoLib/Sources/Categories/Categories.swift @@ -90,7 +90,7 @@ public struct CategoriesView: View { } } } - .buttonStyle(.plain) + .foregroundStyle(.primary) } case .finished(.failure(let error)): APIErrorView(error: error) diff --git a/app/LandinhoLib/Sources/Common/Race.swift b/app/LandinhoLib/Sources/Common/Race.swift index a65d33b..c07f3c4 100644 --- a/app/LandinhoLib/Sources/Common/Race.swift +++ b/app/LandinhoLib/Sources/Common/Race.swift @@ -18,7 +18,7 @@ public struct Race: Codable, Equatable, Identifiable, Hashable { public let id: UUID public let title: String public let shortTitle: String - public let events: [RaceEvent] + public var events: [RaceEvent] } // TODO: Consolidate this into Race instead diff --git a/app/LandinhoLib/Sources/Common/RaceBundle.swift b/app/LandinhoLib/Sources/Common/RaceBundle.swift index 4eb84e5..ae5091b 100644 --- a/app/LandinhoLib/Sources/Common/RaceBundle.swift +++ b/app/LandinhoLib/Sources/Common/RaceBundle.swift @@ -30,6 +30,6 @@ public struct RaceBundle: Codable, Equatable, Identifiable { } public let category: RaceCategory - public let nextRace: Race + public var nextRace: Race public var id: UUID { nextRace.id } } diff --git a/app/LandinhoLib/Sources/EventDetail/EventDetail.swift b/app/LandinhoLib/Sources/EventDetail/EventDetail.swift index 1401e9f..120374b 100644 --- a/app/LandinhoLib/Sources/EventDetail/EventDetail.swift +++ b/app/LandinhoLib/Sources/EventDetail/EventDetail.swift @@ -34,7 +34,7 @@ public struct EventDetail: Reducer { } public enum DelegateAction: Equatable { - case onShareTap(race: MegaRace, isSquareAspectRatio: Bool) + case onShareTap(race: MegaRace) } public var body: some ReducerOf { @@ -140,15 +140,8 @@ struct InnerEventDetailView: View { .navigationTitle(race.shortTitle) .toolbar { ToolbarItem { - Menu { - Button("Instagram", systemImage: "photo") { - store.send(.delegate(.onShareTap(race: race, isSquareAspectRatio: false))) - } - Button("Quadrado", systemImage: "crop") { - store.send(.delegate(.onShareTap(race: race, isSquareAspectRatio: true))) - } - } label: { - Image(systemName: "square.and.arrow.up") + Button("Compartilhar", systemImage: "square.and.arrow.up") { + store.send(.delegate(.onShareTap(race: race))) } } } @@ -168,7 +161,7 @@ struct MainEventsView: View { let events: [RaceEvent] var body: some View { - if events.count == 1 { + if events.count <= 2 { singleEventView } else { multipleEventsView @@ -176,19 +169,26 @@ struct MainEventsView: View { } var singleEventView: some View { - VStack { + VStack(alignment: .leading) { ForEach(events) { event in HStack { Text(event.title) .font(.title) + .scaledToFit() + .minimumScaleFactor(0.01) + Spacer() - Text(event.date.formatted(.dateTime.hour().minute())) - .font(.title) + + VStack(alignment: .trailing) { + Text(event.date.formatted(.dateTime.day().weekday())) + .font(.caption) + Text(event.date.formatted(.dateTime.hour().minute())) + .font(.title) + } } .padding() - .padding(.horizontal) .background(Color(.systemBackground)) - .clipShape(RoundedRectangle(cornerRadius: 25.0, style: .continuous)) + .clipShape(RoundedRectangle(cornerRadius: 15.0, style: .continuous)) .shadow(color: .black.opacity(0.1), radius: 1) } } @@ -202,6 +202,9 @@ struct MainEventsView: View { Text(event.title) .font(.title2) Spacer() + + Text(event.date.formatted(.dateTime.day().weekday())) + .font(.caption) Text(event.date.formatted(.dateTime.hour().minute())) .font(.title) } diff --git a/app/LandinhoLib/Sources/Router/Router.swift b/app/LandinhoLib/Sources/Router/Router.swift index eff2203..580ffec 100644 --- a/app/LandinhoLib/Sources/Router/Router.swift +++ b/app/LandinhoLib/Sources/Router/Router.swift @@ -46,8 +46,11 @@ public struct Router { state.path.append(.eventDetail(.init(race: race))) return .none - case .path(.element(id: _, action: .eventDetail(.delegate(.onShareTap(let race, let isSquareAspectRatio))))): - state.path.append(.sharing(.init(race: race, isSquareAspectRatio: isSquareAspectRatio))) + case + .home(.scheduleList(.delegate(.onShareTap(let race)))), + .path(.element(id: _, action: .eventDetail(.delegate(.onShareTap(let race))))), + .path(.element(id: _, action: .scheduleList(.delegate(.onShareTap(let race))))): + state.path.append(.sharing(.init(race: race))) return .none case .onAppear: diff --git a/app/LandinhoLib/Sources/ScheduleList/ScheduleList.swift b/app/LandinhoLib/Sources/ScheduleList/ScheduleList.swift index 14741ec..403462d 100644 --- a/app/LandinhoLib/Sources/ScheduleList/ScheduleList.swift +++ b/app/LandinhoLib/Sources/ScheduleList/ScheduleList.swift @@ -46,6 +46,7 @@ public struct ScheduleList: Reducer { public enum DelegateAction: Equatable { case onWidgetTap(MegaRace) + case onShareTap(MegaRace) } public var body: some ReducerOf { diff --git a/app/LandinhoLib/Sources/ScheduleList/Views/ScheduleListView.swift b/app/LandinhoLib/Sources/ScheduleList/Views/ScheduleListView.swift index 23c2022..c1291bd 100644 --- a/app/LandinhoLib/Sources/ScheduleList/Views/ScheduleListView.swift +++ b/app/LandinhoLib/Sources/ScheduleList/Views/ScheduleListView.swift @@ -30,73 +30,24 @@ public struct ScheduleListView: View { case .loading: ProgressView() case .reloading(let response), .finished(.success(let response)): - // TODO: Empty State ScrollView { - VStack(spacing: 20) { - VStack { - Text("Ainda não tem nada por aqui, mas se você quiser ver, esse são os Widgets do app por enquanto:") - .frame(maxWidth: .infinity, alignment: .leading) - Text("*Toca neles pra ir pra tela da corrida*") - .font(.caption) - .foregroundStyle(.secondary) - .frame(maxWidth: .infinity, alignment: .leading) - } - .padding(.horizontal) - - ScrollView(.horizontal) { - HStack { - Spacer().padding(.leading, 5) - ForEach(response.items) { item in - NextRaceSmallWidgetView(bundle: item.bundled, lastUpdatedDate: Date()) - .widgetBackground() - .widgetFrame(family: .systemSmall) - .onTapAnimate { - viewStore.send(.delegate(.onWidgetTap(item))) - } - } - Spacer().padding(.trailing, 5) - } - } - .scrollClipDisabled() - .scrollIndicators(.hidden) - - ScrollView(.horizontal) { - HStack { - Spacer().padding(.leading, 5) - ForEach(response.items) { item in - NextRaceMediumWidgetView(bundle: item.bundled, lastUpdatedDate: Date()) - .widgetBackground() - .widgetFrame(family: .systemMedium) - .onTapAnimate { - viewStore.send(.delegate(.onWidgetTap(item))) - } + LazyVStack(spacing: 20) { + ForEach(response.items) { item in + NextRaceMediumWidgetView(bundle: item.bundled, lastUpdatedDate: Date()) + .widgetBackground() + .widgetFrame(family: .systemMedium) + .onTapAnimate { + viewStore.send(.delegate(.onWidgetTap(item))) } - Spacer().padding(.trailing, 5) - } - } - .scrollClipDisabled() - .scrollIndicators(.hidden) - - ScrollView(.horizontal) { - HStack { - Spacer().padding(.leading, 5) - ForEach(response.items) { item in - NextRaceLargeWidgetView(bundle: item.bundled, lastUpdatedDate: Date()) - .widgetBackground() - .widgetFrame(family: .systemLarge) - .onTapAnimate { - viewStore.send(.delegate(.onWidgetTap(item))) - } + .contextMenu { + Button("Compartilhar", systemImage: "square.and.arrow.up") { + viewStore.send(.delegate(.onShareTap(item))) + } } - Spacer().padding(.trailing, 5) - } } - .scrollClipDisabled() - .scrollIndicators(.hidden) - - Spacer().frame(height: 50) } } + .frame(maxWidth: .infinity) .background( .background.secondary ) diff --git a/app/LandinhoLib/Sources/Sharing/Assets.xcassets/AppIcon.imageset/Contents.json b/app/LandinhoLib/Sources/Sharing/Assets.xcassets/AppIcon.imageset/Contents.json index adc7499..b6f10aa 100644 --- a/app/LandinhoLib/Sources/Sharing/Assets.xcassets/AppIcon.imageset/Contents.json +++ b/app/LandinhoLib/Sources/Sharing/Assets.xcassets/AppIcon.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Race Car Illustration DALL·E.png", + "filename" : "Race Car Illustration Sao Paulo.png", "idiom" : "universal" } ], diff --git "a/app/LandinhoLib/Sources/Sharing/Assets.xcassets/AppIcon.imageset/Race Car Illustration DALL\302\267E.png" "b/app/LandinhoLib/Sources/Sharing/Assets.xcassets/AppIcon.imageset/Race Car Illustration DALL\302\267E.png" deleted file mode 100644 index 3bf2c00..0000000 Binary files "a/app/LandinhoLib/Sources/Sharing/Assets.xcassets/AppIcon.imageset/Race Car Illustration DALL\302\267E.png" and /dev/null differ diff --git a/app/LandinhoLib/Sources/Sharing/Assets.xcassets/AppIcon.imageset/Race Car Illustration Sao Paulo.png b/app/LandinhoLib/Sources/Sharing/Assets.xcassets/AppIcon.imageset/Race Car Illustration Sao Paulo.png new file mode 100644 index 0000000..3bff92d Binary files /dev/null and b/app/LandinhoLib/Sources/Sharing/Assets.xcassets/AppIcon.imageset/Race Car Illustration Sao Paulo.png differ diff --git a/app/LandinhoLib/Sources/Sharing/Sharing.swift b/app/LandinhoLib/Sources/Sharing/Sharing.swift index 7916a7c..80be3da 100644 --- a/app/LandinhoLib/Sources/Sharing/Sharing.swift +++ b/app/LandinhoLib/Sources/Sharing/Sharing.swift @@ -15,16 +15,12 @@ public struct Sharing { public init() {} public struct State: Equatable { - public init( - race: MegaRace, - isSquareAspectRatio: Bool - ) { + public init(race: MegaRace) { self.race = race - self.isSquareAspectRatio = isSquareAspectRatio } let race: MegaRace - let isSquareAspectRatio: Bool + var isSquareAspectRatio: Bool = true var currentWidgetType: ShareableWidgetType = .systemMedium var hasTappedShare: Bool = false var renderedImage: UIImage? = nil @@ -36,6 +32,7 @@ public struct Sharing { case onWidgetTap case onShareTap case onDismissShare + case toggleAspectRatio case onRender(UIImage) case binding(BindingAction) } @@ -54,6 +51,9 @@ public struct Sharing { case .onWidgetTap: state.currentWidgetType = ShareableWidgetType.allCases.next(element: state.currentWidgetType) return .none + case .toggleAspectRatio: + state.isSquareAspectRatio.toggle() + return .none case .onRender(let image): state.renderedImage = image state.isSharing = true diff --git a/app/LandinhoLib/Sources/Sharing/Views/SharingRenderableView.swift b/app/LandinhoLib/Sources/Sharing/Views/SharingRenderableView.swift index 2756381..798b5c6 100644 --- a/app/LandinhoLib/Sources/Sharing/Views/SharingRenderableView.swift +++ b/app/LandinhoLib/Sources/Sharing/Views/SharingRenderableView.swift @@ -36,8 +36,8 @@ struct SharingRenderableView: View { } } -#Preview("Instagram Renderable") { - var state = Sharing.State(race: .mock, isSquareAspectRatio: true) +#Preview("16/9 Renderable") { + var state = Sharing.State(race: .mock) state.hasTappedShare = true let store = Store(initialState: state) { Sharing() @@ -49,7 +49,7 @@ struct SharingRenderableView: View { } #Preview("Square Renderable", traits: .fixedLayout(width: 360, height: 360)) { - var state = Sharing.State(race: .mock, isSquareAspectRatio: true) + var state = Sharing.State(race: .mock) state.hasTappedShare = true let store = Store(initialState: state) { Sharing() diff --git a/app/LandinhoLib/Sources/Sharing/Views/SharingView.swift b/app/LandinhoLib/Sources/Sharing/Views/SharingView.swift index bc9c7df..03405cc 100644 --- a/app/LandinhoLib/Sources/Sharing/Views/SharingView.swift +++ b/app/LandinhoLib/Sources/Sharing/Views/SharingView.swift @@ -33,7 +33,7 @@ public struct SharingView: View { .frame(height: viewStore.isSquareAspectRatio ? 360 : 640) dismissButton(viewStore) - + cropButton(viewStore) shareButton(viewStore) } .sheet(isPresented: viewStore.$isSharing, onDismiss: { @@ -106,6 +106,23 @@ public struct SharingView: View { .frame(maxHeight: .infinity, alignment: .bottom) } + @MainActor + func cropButton(_ viewStore: ViewStoreOf) -> some View { + Button(action: { + withAnimation { + _ = viewStore.send(.toggleAspectRatio) + } + }, label: { + Image(systemName: "crop") + .bold() + }) + .frame(width: 50, height: 50) + .contentShape(Rectangle()) + .foregroundStyle(.white) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomTrailing) + .opacity(viewStore.hasTappedShare ? 0 : 1) + } + @MainActor func render(isSquareAspectRatio: Bool) { let renderer = ImageRenderer(content: SharingRenderableView(store: store)) @@ -123,27 +140,12 @@ public struct SharingView: View { } } -#Preview("Instagram Ratio") { - NavigationStack { - NavigationLink { - SharingView(store: .init(initialState: .init(race: .mock, isSquareAspectRatio: false), reducer: { - Sharing() - })) - } label: { - Text("push") - } - .navigationTitle("push") - .navigationBarTitleDisplayMode(.large) - } -} - -#Preview("Square Ratio") { - SharingView(store: .init(initialState: .init(race: .mock, isSquareAspectRatio: true), reducer: { +#Preview { + SharingView(store: .init(initialState: .init(race: .mock), reducer: { Sharing() })) } - private struct ActivityView: UIViewControllerRepresentable { var activityItems: [Any] var applicationActivities: [UIActivity]? = nil diff --git a/app/LandinhoLib/Sources/Sharing/Views/WidgetSelectorView.swift b/app/LandinhoLib/Sources/Sharing/Views/WidgetSelectorView.swift index 21a6bc9..ca5c437 100644 --- a/app/LandinhoLib/Sources/Sharing/Views/WidgetSelectorView.swift +++ b/app/LandinhoLib/Sources/Sharing/Views/WidgetSelectorView.swift @@ -54,7 +54,7 @@ private extension View { } #Preview { - var state = Sharing.State(race: .mock, isSquareAspectRatio: true) + var state = Sharing.State(race: .mock) let store = Store(initialState: state) { Sharing() } diff --git a/app/VroomVroom.xcodeproj/xcshareddata/xcschemes/WidgetsExtension.xcscheme b/app/VroomVroom.xcodeproj/xcshareddata/xcschemes/WidgetsExtension (systemMedium).xcscheme similarity index 88% rename from app/VroomVroom.xcodeproj/xcshareddata/xcschemes/WidgetsExtension.xcscheme rename to app/VroomVroom.xcodeproj/xcshareddata/xcschemes/WidgetsExtension (systemMedium).xcscheme index 95706c1..6c45f24 100644 --- a/app/VroomVroom.xcodeproj/xcshareddata/xcschemes/WidgetsExtension.xcscheme +++ b/app/VroomVroom.xcodeproj/xcshareddata/xcschemes/WidgetsExtension (systemMedium).xcscheme @@ -56,8 +56,18 @@ debugServiceExtension = "internal" allowLocationSimulation = "YES" launchAutomaticallySubstyle = "2"> - + + + + + - +