Update source code with grid layout and channel management

Major changes:
- Add ChannelAdapter for grid display functionality
- Add ChannelRepository for data management
- Add PlayerActivity for dedicated video playback
- Add StreamChannel model for channel representation
- Update MainActivity to support grid layout
- Update activity_main.xml with grid UI components
- Add channel item layouts and drawables
- Update AndroidManifest.xml with new activity
- Update build.gradle dependencies

This implements the requested "grilla arreglada" functionality with proper channel grid display and management.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-14 18:50:54 +00:00
parent d861eca52f
commit e6b4d0825b
13 changed files with 537 additions and 168 deletions

View File

@@ -1,157 +1,29 @@
package com.streamplayer;
import android.content.Intent;
import android.os.Bundle;
import android.os.StrictMode;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.ui.PlayerView;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class MainActivity extends AppCompatActivity {
private ExoPlayer player;
private PlayerView playerView;
private ProgressBar loadingIndicator;
private TextView errorMessage;
private static final String STREAM_PAGE_URL = "https://streamtpmedia.com/global2.php?stream=espn";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Configurar política de red para allow cleartext traffic
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
setContentView(R.layout.activity_main);
initViews();
// Configurar DNS de Google para streaming
DNSSetter.configureDNSToGoogle(this);
initializePlayer();
}
private void initViews() {
playerView = findViewById(R.id.player_view);
loadingIndicator = findViewById(R.id.loading_indicator);
errorMessage = findViewById(R.id.error_message);
}
private void initializePlayer() {
showLoading(true);
new Thread(() -> {
try {
String resolvedUrl = StreamUrlResolver.resolve(STREAM_PAGE_URL);
runOnUiThread(() -> startPlayback(resolvedUrl));
} catch (Exception e) {
runOnUiThread(() -> showError("Error al obtener stream: " + e.getMessage()));
}
}).start();
}
private void startPlayback(String streamUrl) {
try {
releasePlayer();
player = new ExoPlayer.Builder(this).build();
playerView.setPlayer(player);
player.addListener(new Player.Listener() {
@Override
public void onPlaybackStateChanged(int playbackState) {
switch (playbackState) {
case Player.STATE_BUFFERING:
showLoading(true);
break;
case Player.STATE_READY:
showLoading(false);
break;
case Player.STATE_ENDED:
// Video terminado
break;
}
}
@Override
public void onPlayerError(PlaybackException error) {
showError("Error al reproducir: " + error.getMessage());
}
});
MediaItem mediaItem = MediaItem.fromUri(streamUrl);
player.setMediaItem(mediaItem);
player.prepare();
player.setPlayWhenReady(true);
} catch (Exception e) {
showError("Error al inicializar reproductor: " + e.getMessage());
}
}
private void showLoading(boolean show) {
loadingIndicator.setVisibility(show ? View.VISIBLE : View.GONE);
errorMessage.setVisibility(View.GONE);
playerView.setVisibility(show ? View.GONE : View.VISIBLE);
}
private void showError(String message) {
loadingIndicator.setVisibility(View.GONE);
playerView.setVisibility(View.GONE);
errorMessage.setVisibility(View.VISIBLE);
errorMessage.setText(message);
}
@Override
protected void onStart() {
super.onStart();
if (player != null) {
playerView.onResume();
}
}
@Override
protected void onResume() {
super.onResume();
if (player != null) {
playerView.onResume();
}
}
@Override
protected void onPause() {
super.onPause();
if (player != null) {
playerView.onPause();
}
}
@Override
protected void onStop() {
super.onStop();
if (player != null) {
playerView.onPause();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
releasePlayer();
}
private void releasePlayer() {
if (player != null) {
player.release();
player = null;
}
RecyclerView recyclerView = findViewById(R.id.channel_grid);
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
ChannelAdapter adapter = 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);
});
recyclerView.setAdapter(adapter);
}
}