Add v7.0: Tabs UI and Real-Time Events
Major Features: - Dual tab interface (Channels and Events) with visible focus - Real-time event status calculation (Live, Upcoming, Finished) - Smart caching system for events (24-hour cache) - Argentina timezone support (America/Argentina/Buenos_Aires) UI/TV Improvements: - Focusable tabs with bg_tab_selector for D-pad navigation - Visual feedback with highlighted borders on focused tabs - Consistent design between tabs and content cards - Enhanced TV navigation experience Real-Time Event System: - EventRepository: Centralized event management with 24h cache - EventAdapter: Optimized RecyclerView for event listings - EventItem: Structured data model for events - Dynamic status calculation (remaining time, live duration, completion) - Automatic link normalization to global2.php Technical Implementation: - activity_main.xml: Complete dual-tab layout - item_event.xml: Dedicated event item layout with RecyclerView - bg_tab_selector.xml: Tab states (selected, focused, pressed) - MainActivity.java: Tab switching and event management - Automatic URL processing for seamless PlayerActivity integration Time Zone Features: - Argentina local time (America/Argentina/Buenos_Aires) - Real-time status updates without page refresh - "En Xh Ym" for upcoming events - "En vivo durante 2h" status for live events - "Finalizado" status for completed events Solutions: - Fixed web page "En vivo" not updating issue - Provides always-current event status in app - Direct event-to-player navigation without manual intervention - Improved TV navigation with clear visual feedback 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2,31 +2,112 @@ package com.streamplayer;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private RecyclerView channelGrid;
|
||||
private RecyclerView eventsList;
|
||||
private View eventsContainer;
|
||||
private ProgressBar eventsProgress;
|
||||
private TextView eventsError;
|
||||
private Button tabChannels;
|
||||
private Button tabEvents;
|
||||
|
||||
private EventAdapter eventAdapter;
|
||||
private EventRepository eventRepository;
|
||||
private boolean eventsLoaded = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
RecyclerView recyclerView = findViewById(R.id.channel_grid);
|
||||
recyclerView.setLayoutManager(new GridLayoutManager(this, getSpanCount()));
|
||||
recyclerView.setHasFixedSize(true);
|
||||
ChannelAdapter adapter = new ChannelAdapter(
|
||||
channelGrid = findViewById(R.id.channel_grid);
|
||||
eventsList = findViewById(R.id.events_list);
|
||||
eventsContainer = findViewById(R.id.events_container);
|
||||
eventsProgress = findViewById(R.id.events_progress);
|
||||
eventsError = findViewById(R.id.events_error);
|
||||
tabChannels = findViewById(R.id.tab_channels);
|
||||
tabEvents = findViewById(R.id.tab_events);
|
||||
|
||||
channelGrid.setLayoutManager(new GridLayoutManager(this, getSpanCount()));
|
||||
channelGrid.setHasFixedSize(true);
|
||||
ChannelAdapter channelAdapter = new ChannelAdapter(
|
||||
ChannelRepository.getChannels(),
|
||||
channel -> {
|
||||
Intent intent = new Intent(MainActivity.this, PlayerActivity.class);
|
||||
intent.putExtra(PlayerActivity.EXTRA_CHANNEL_NAME, channel.getName());
|
||||
intent.putExtra(PlayerActivity.EXTRA_CHANNEL_URL, channel.getPageUrl());
|
||||
startActivity(intent);
|
||||
channel -> openPlayer(channel.getName(), channel.getPageUrl()));
|
||||
channelGrid.setAdapter(channelAdapter);
|
||||
|
||||
eventsList.setLayoutManager(new GridLayoutManager(this, 1));
|
||||
eventAdapter = new EventAdapter(event -> openPlayer(event.getTitle(), event.getPageUrl()));
|
||||
eventsList.setAdapter(eventAdapter);
|
||||
|
||||
eventRepository = new EventRepository();
|
||||
|
||||
tabChannels.setOnClickListener(v -> showChannels());
|
||||
tabEvents.setOnClickListener(v -> showEvents());
|
||||
|
||||
showChannels();
|
||||
channelGrid.post(channelGrid::requestFocus);
|
||||
}
|
||||
|
||||
private void showChannels() {
|
||||
channelGrid.setVisibility(View.VISIBLE);
|
||||
eventsContainer.setVisibility(View.GONE);
|
||||
tabChannels.setSelected(true);
|
||||
tabEvents.setSelected(false);
|
||||
}
|
||||
|
||||
private void showEvents() {
|
||||
channelGrid.setVisibility(View.GONE);
|
||||
eventsContainer.setVisibility(View.VISIBLE);
|
||||
tabChannels.setSelected(false);
|
||||
tabEvents.setSelected(true);
|
||||
if (!eventsLoaded) {
|
||||
loadEvents(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadEvents(boolean forceRefresh) {
|
||||
eventsProgress.setVisibility(View.VISIBLE);
|
||||
eventsError.setVisibility(View.GONE);
|
||||
eventsList.setVisibility(View.GONE);
|
||||
eventRepository.loadEvents(this, forceRefresh, new EventRepository.Callback() {
|
||||
@Override
|
||||
public void onSuccess(List<EventItem> events) {
|
||||
runOnUiThread(() -> {
|
||||
eventsProgress.setVisibility(View.GONE);
|
||||
eventAdapter.submitList(events);
|
||||
eventsList.setVisibility(View.VISIBLE);
|
||||
eventsLoaded = true;
|
||||
});
|
||||
recyclerView.setAdapter(adapter);
|
||||
recyclerView.post(recyclerView::requestFocus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String message) {
|
||||
runOnUiThread(() -> {
|
||||
eventsProgress.setVisibility(View.GONE);
|
||||
eventsError.setText("No se pudieron cargar los eventos: " + message);
|
||||
eventsError.setVisibility(View.VISIBLE);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void openPlayer(String name, String pageUrl) {
|
||||
Intent intent = new Intent(MainActivity.this, PlayerActivity.class);
|
||||
intent.putExtra(PlayerActivity.EXTRA_CHANNEL_NAME, name);
|
||||
intent.putExtra(PlayerActivity.EXTRA_CHANNEL_URL, pageUrl);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private int getSpanCount() {
|
||||
|
||||
Reference in New Issue
Block a user