Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New app view #2

Open
wants to merge 5 commits into
base: new_home_page
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
android:name=".AppView"
android:resizeableActivity="true"
android:enableOnBackInvokedCallback="true"
android:theme="@style/MaterialAppTheme"
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
Expand Down Expand Up @@ -202,7 +203,7 @@
</activity>

<activity android:name=".shagaProtocol.PairingActivity"
android:theme="@style/RentingActivityTheme">
android:theme="@style/AppTheme">
<!-- Add intent filters here if necessary -->
</activity>

Expand Down
95 changes: 58 additions & 37 deletions app/src/main/java/com/limelight/AppView.java
Original file line number Diff line number Diff line change
@@ -1,28 +1,5 @@
package com.limelight;

import java.io.IOException;
import java.io.StringReader;
import java.util.HashSet;
import java.util.List;

import com.limelight.computers.ComputerManagerListener;
import com.limelight.computers.ComputerManagerService;
import com.limelight.grid.AppGridAdapter;
import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.nvstream.http.NvApp;
import com.limelight.nvstream.http.NvHTTP;
import com.limelight.nvstream.http.PairingManager;
import com.limelight.preferences.PreferenceConfiguration;
import com.limelight.ui.AdapterFragment;
import com.limelight.ui.AdapterFragmentCallbacks;
import com.limelight.utils.CacheHelper;
import com.limelight.utils.Dialog;
import com.limelight.utils.ServerHelper;
import com.limelight.utils.ShortcutHelper;
import com.limelight.utils.SpinnerDialog;
import com.limelight.utils.UiHelper;

import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
Expand All @@ -35,23 +12,52 @@
import android.os.Bundle;
import android.os.IBinder;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;

import com.limelight.computers.ComputerManagerListener;
import com.limelight.computers.ComputerManagerService;
import com.limelight.grid.AppGridAdapter;
import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.nvstream.http.NvApp;
import com.limelight.nvstream.http.NvHTTP;
import com.limelight.nvstream.http.PairingManager;
import com.limelight.preferences.PreferenceConfiguration;
import com.limelight.shaga.ui.main.games.AppViewFragment;
import com.limelight.shaga.ui.main.games.AppViewFragmentCallback;
import com.limelight.shaga.ui.main.games.GameListViewModel;
import com.limelight.ui.AdapterFragment;
import com.limelight.ui.AdapterFragmentCallbacks;
import com.limelight.utils.CacheHelper;
import com.limelight.utils.Dialog;
import com.limelight.utils.ServerHelper;
import com.limelight.utils.ShortcutHelper;
import com.limelight.utils.SpinnerDialog;
import com.limelight.utils.UiHelper;

import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.StringReader;
import java.util.HashSet;
import java.util.List;

// Shaga

public class AppView extends Activity implements AdapterFragmentCallbacks {
public class AppView extends AppCompatActivity implements AdapterFragmentCallbacks, AppViewFragmentCallback {
private AppGridAdapter appGridAdapter;
private String uuidString;
private ShortcutHelper shortcutHelper;
Expand Down Expand Up @@ -79,6 +85,9 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
public final static String UUID_EXTRA = "UUID";
public final static String NEW_PAIR_EXTRA = "NewPair";
public final static String SHOW_HIDDEN_APPS_EXTRA = "ShowHiddenApps";
public final static String IP_ADDRESS_EXTRA = "ipAddress";

private GameListViewModel viewModel;

private ComputerManagerService.ComputerManagerBinder managerBinder;
private final ServiceConnection serviceConnection = new ServiceConnection() {
Expand Down Expand Up @@ -108,7 +117,7 @@ public void run() {
appGridAdapter = new AppGridAdapter(AppView.this,
PreferenceConfiguration.readPreferences(AppView.this),
computer, localBinder.getUniqueId(),
showHiddenApps);
showHiddenApps, viewModel);
} catch (Exception e) {
e.printStackTrace();
finish();
Expand Down Expand Up @@ -285,6 +294,9 @@ private void stopComputerUpdates() {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

viewModel = new ViewModelProvider(this).get(GameListViewModel.class);
viewModel.setIpAddress(getIntent().getStringExtra(IP_ADDRESS_EXTRA));

// Assume we're in the foreground when created to avoid a race
// between binding to CMS and onResume()
inForeground = true;
Expand Down Expand Up @@ -313,12 +325,12 @@ protected void onCreate(Bundle savedInstanceState) {
String computerName = getIntent().getStringExtra(NAME_EXTRA);

TextView label = findViewById(R.id.appListText);
setTitle(computerName);
label.setText(computerName);




getSupportFragmentManager()
.beginTransaction()
.replace(R.id.newUiContainer, new AppViewFragment())
.commit();

// Bind to the computer manager service
bindService(new Intent(this, ComputerManagerService.class), serviceConnection,
Expand Down Expand Up @@ -638,19 +650,28 @@ public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
long id) {
AppObject app = (AppObject) appGridAdapter.getItem(pos);

// Only open the context menu if something is running, otherwise start it
if (lastRunningAppId != 0) {
openContextMenu(arg1);
} else {
ServerHelper.doStart(AppView.this, app.app, computer, managerBinder);
}
openApp(app, arg1);
}
});
UiHelper.applyStatusBarPadding(listView);
registerForContextMenu(listView);
listView.requestFocus();
}

private void openApp(AppObject app, View view) {
// Only open the context menu if something is running, otherwise start it
if (lastRunningAppId != 0 && view != null) {
openContextMenu(view);
} else {
ServerHelper.doStart(AppView.this, app.app, computer, managerBinder);
}
}

@Override
public void onAppClick(@NonNull AppObject app) {
openApp(app, null);
}

public static class AppObject {
public final NvApp app;
public boolean isRunning;
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/limelight/PcView.java
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ private static class CheckRentalStatusTask extends AsyncTask<Void, Void, Boolean

@Override
protected Boolean doInBackground(Void... params) {
return ShagaTransactions.TransactionsObject.checkRentalStatus();
return ShagaTransactions.TransactionsObject.checkRentalStatus() != null;
}

@Override
Expand Down
9 changes: 8 additions & 1 deletion app/src/main/java/com/limelight/grid/AppGridAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.limelight.grid.assets.NetworkAssetLoader;
import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.preferences.PreferenceConfiguration;
import com.limelight.shaga.ui.main.games.GameListViewModel;

import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -33,17 +34,19 @@ public class AppGridAdapter extends GenericGridAdapter<AppView.AppObject> {
private final ComputerDetails computer;
private final String uniqueId;
private final boolean showHiddenApps;
private GameListViewModel viewModel;

private CachedAppAssetLoader loader;
private Set<Integer> hiddenAppIds = new HashSet<>();
private ArrayList<AppView.AppObject> allApps = new ArrayList<>();

public AppGridAdapter(Context context, PreferenceConfiguration prefs, ComputerDetails computer, String uniqueId, boolean showHiddenApps) {
public AppGridAdapter(Context context, PreferenceConfiguration prefs, ComputerDetails computer, String uniqueId, boolean showHiddenApps, GameListViewModel viewModel) {
super(context, getLayoutIdForPreferences(prefs));

this.computer = computer;
this.uniqueId = uniqueId;
this.showHiddenApps = showHiddenApps;
this.viewModel = viewModel;

updateLayoutWithPreferences(context, prefs);
}
Expand All @@ -69,6 +72,7 @@ public void updateHiddenApps(Set<Integer> newHiddenAppIds, boolean hideImmediate
app.isHidden = hiddenAppIds.contains(app.app.getAppId());
}
}
viewModel.update(itemList);

notifyDataSetChanged();
}
Expand Down Expand Up @@ -147,11 +151,14 @@ public void addApp(AppView.AppObject app) {
itemList.add(app);
sortList(itemList);
}

viewModel.update(itemList);
}

public void removeApp(AppView.AppObject app) {
itemList.remove(app);
allApps.remove(app);
viewModel.update(itemList);
}

@Override
Expand Down
23 changes: 23 additions & 0 deletions app/src/main/java/com/limelight/shaga/ui/ScreenDestination.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.limelight.shaga.ui

import androidx.compose.runtime.Composable
import androidx.navigation.NamedNavArgument
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable

abstract class ScreenDestination {
abstract val route: String

protected open val arguments: List<NamedNavArgument>
get() = emptyList()

fun register(builder: NavGraphBuilder) {
builder.composable(route, arguments) { navBackStackEntry ->
Content(navBackStackEntry)
}
}

@Composable
abstract fun Content(navBackStackEntry: NavBackStackEntry)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.limelight.shaga.ui.connection

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.limelight.R
import com.limelight.shaga.ui.kit.ProfileButton
import com.limelight.shaga.ui.kit.ShagaColors
import com.limelight.shaga.ui.kit.ShagaTheme
import com.limelight.shaga.ui.kit.ShagaTopBar

@Composable
fun ConnectionScreen(uiState: ConnectionScreenState, onRetryClick: () -> Unit) {
Scaffold(
containerColor = ShagaColors.Background2,
contentColor = Color.White,
topBar = {
ShagaTopBar {
ProfileButton(
text = "",
onClick = {},
isLoading = true,
modifier = Modifier.padding(top = 2.dp)
)
}
}
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Icon(
painterResource(R.drawable.ic_laptop_100dp),
null,
tint = ShagaColors.TextSecondary2,
modifier = Modifier.size(100.dp)
)
Text(
text = uiState.message.uppercase(),
style = MaterialTheme.typography.labelMedium.copy(fontSize = 13.sp),
textAlign = TextAlign.Center,
modifier = Modifier.padding(top = 8.dp)
)
if (uiState.isError) {
TextButton(onClick = onRetryClick, modifier = Modifier.padding(top = 8.dp)) {
Text("Retry")
}
}
}
}
}

@Preview
@Composable
private fun Preview() {
ShagaTheme {
ConnectionScreen(ConnectionScreenState("Connecting", false), onRetryClick = {})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.limelight.shaga.ui.connection

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NamedNavArgument
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavType
import androidx.navigation.navArgument
import com.limelight.shaga.ui.ScreenDestination

object ConnectionScreenDestination : ScreenDestination() {
private const val baseRoute = "connection"
private const val clientAccountArg = "clientAccount"
private const val ipAddressArg = "ipAddress"
private const val authorityArg = "authority"

override val route: String = "$baseRoute/{$clientAccountArg}/{$ipAddressArg}/{$authorityArg}"

override val arguments: List<NamedNavArgument>
get() = listOf(
navArgument(clientAccountArg) { type = NavType.StringType },
navArgument(ipAddressArg) { type = NavType.StringType },
navArgument(authorityArg) { type = NavType.StringType }
)

fun navigationRoute(clientAccount: String, ipAddress: String, authority: String): String {
return "$baseRoute/$clientAccount/$ipAddress/$authority"
}

@Composable
override fun Content(navBackStackEntry: NavBackStackEntry) {
val clientAccount = navBackStackEntry.arguments?.getString(clientAccountArg)!!
val ipAddress = navBackStackEntry.arguments?.getString(ipAddressArg)!!
val authority = navBackStackEntry.arguments?.getString(authorityArg)!!

val viewModel = viewModel { ConnectionScreenViewModel() }
val uiState by viewModel.uiState.collectAsStateWithLifecycle()

ConnectionScreen(uiState, onRetryClick = {})
}
}
Loading